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
159 // If only accessible to the current class or children
161 if (ma == MethodAttributes.Private)
162 return invocation_type == mi.DeclaringType ||
163 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
165 if (mi.DeclaringType.Assembly == invocation_type.Assembly) {
166 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
169 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
173 // Family and FamANDAssem require that we derive.
174 // FamORAssem requires that we derive if in different assemblies.
175 if (ma == MethodAttributes.Family ||
176 ma == MethodAttributes.FamANDAssem ||
177 ma == MethodAttributes.FamORAssem) {
178 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
181 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
182 must_do_cs1540_check = true;
191 /// Performs semantic analysis on the Expression
195 /// The Resolve method is invoked to perform the semantic analysis
198 /// The return value is an expression (it can be the
199 /// same expression in some cases) or a new
200 /// expression that better represents this node.
202 /// For example, optimizations of Unary (LiteralInt)
203 /// would return a new LiteralInt with a negated
206 /// If there is an error during semantic analysis,
207 /// then an error should be reported (using Report)
208 /// and a null value should be returned.
210 /// There are two side effects expected from calling
211 /// Resolve(): the the field variable "eclass" should
212 /// be set to any value of the enumeration
213 /// `ExprClass' and the type variable should be set
214 /// to a valid type (this is the type of the
217 public abstract Expression DoResolve (EmitContext ec);
219 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
225 // This is used if the expression should be resolved as a type or namespace name.
226 // the default implementation fails.
228 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
234 // This is used to resolve the expression as a type, a null
235 // value will be returned if the expression is not a type
238 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
240 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
244 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
245 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
246 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
251 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
253 int errors = Report.Errors;
255 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
258 if (!silent && errors == Report.Errors)
259 Report.Error (118, loc, "Expecting a type.");
263 if (fne.eclass != ExprClass.Type) {
264 if (!silent && errors == Report.Errors)
265 fne.Error_UnexpectedKind (null, "type", loc);
269 TypeExpr te = fne as TypeExpr;
271 if (!te.CheckAccessLevel (ec.DeclContainer)) {
272 Report.SymbolRelatedToPreviousError (te.Type);
273 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
281 public static void ErrorIsInaccesible (Location loc, string name)
283 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
286 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
288 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
289 + " the qualifier must be of type `{2}' (or derived from it)",
290 TypeManager.GetFullNameSignature (m),
291 TypeManager.CSharpName (qualifier),
292 TypeManager.CSharpName (container));
296 public static void Error_VoidInvalidInTheContext (Location loc)
298 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
301 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
303 if (Type.Name == target.Name){
304 Report.ExtraInformation (loc,
306 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
307 Type.Name, Type.Assembly.FullName, target.Assembly.FullName));
312 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
313 GetSignatureForError (), TypeManager.CSharpName (target));
317 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
318 bool b = Convert.ExplicitNumericConversion (e, target) != null;
320 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
321 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
322 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
326 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
327 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
328 GetSignatureForError (), TypeManager.CSharpName (target));
332 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
333 Type == TypeManager.anonymous_method_type ?
334 "anonymous method" : "`" + GetSignatureForError () + "'",
335 TypeManager.CSharpName (target));
338 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
340 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
341 TypeManager.CSharpName (type), name);
344 ResolveFlags ExprClassToResolveFlags
349 case ExprClass.Namespace:
350 return ResolveFlags.Type;
352 case ExprClass.MethodGroup:
353 return ResolveFlags.MethodGroup;
355 case ExprClass.Value:
356 case ExprClass.Variable:
357 case ExprClass.PropertyAccess:
358 case ExprClass.EventAccess:
359 case ExprClass.IndexerAccess:
360 return ResolveFlags.VariableOrValue;
363 throw new Exception ("Expression " + GetType () +
364 " ExprClass is Invalid after resolve");
370 /// Resolves an expression and performs semantic analysis on it.
374 /// Currently Resolve wraps DoResolve to perform sanity
375 /// checking and assertion checking on what we expect from Resolve.
377 public Expression Resolve (EmitContext ec, ResolveFlags flags)
379 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
380 return ResolveAsTypeStep (ec, false);
382 bool do_flow_analysis = ec.DoFlowAnalysis;
383 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
384 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
385 do_flow_analysis = false;
386 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
387 omit_struct_analysis = true;
390 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
391 if (this is SimpleName) {
392 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
393 e = ((SimpleName) this).DoResolve (ec, intermediate);
402 if ((flags & e.ExprClassToResolveFlags) == 0) {
403 e.Error_UnexpectedKind (flags, loc);
407 if (e.type == null && !(e is Namespace)) {
408 throw new Exception (
409 "Expression " + e.GetType () +
410 " did not set its type after Resolve\n" +
411 "called from: " + this.GetType ());
418 /// Resolves an expression and performs semantic analysis on it.
420 public Expression Resolve (EmitContext ec)
422 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
424 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
425 ((MethodGroupExpr) e).ReportUsageError ();
431 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
433 Expression e = Resolve (ec);
437 Constant c = e as Constant;
441 Type constant_type = null;
442 if (mc is MemberBase) {
443 constant_type = ((MemberBase)mc).MemberType;
446 Const.Error_ExpressionMustBeConstant (constant_type, loc, mc.GetSignatureForError ());
451 /// Resolves an expression for LValue assignment
455 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
456 /// checking and assertion checking on what we expect from Resolve
458 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
460 int errors = Report.Errors;
461 bool out_access = right_side == EmptyExpression.OutAccess;
463 Expression e = DoResolveLValue (ec, right_side);
465 if (e != null && out_access && !(e is IMemoryLocation)) {
466 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
467 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
469 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
470 // e.GetType () + " " + e.GetSignatureForError ());
475 if (errors == Report.Errors) {
477 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
479 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
484 if (e.eclass == ExprClass.Invalid)
485 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
487 if (e.eclass == ExprClass.MethodGroup) {
488 ((MethodGroupExpr) e).ReportUsageError ();
493 throw new Exception ("Expression " + e + " did not set its type after Resolve");
499 /// Emits the code for the expression
503 /// The Emit method is invoked to generate the code
504 /// for the expression.
506 public abstract void Emit (EmitContext ec);
508 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
511 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
515 /// Protected constructor. Only derivate types should
516 /// be able to be created
519 protected Expression ()
521 eclass = ExprClass.Invalid;
526 /// Returns a literalized version of a literal FieldInfo
530 /// The possible return values are:
531 /// IntConstant, UIntConstant
532 /// LongLiteral, ULongConstant
533 /// FloatConstant, DoubleConstant
536 /// The value returned is already resolved.
538 public static Constant Constantify (object v, Type t)
540 if (t == TypeManager.int32_type)
541 return new IntConstant ((int) v, Location.Null);
542 else if (t == TypeManager.uint32_type)
543 return new UIntConstant ((uint) v, Location.Null);
544 else if (t == TypeManager.int64_type)
545 return new LongConstant ((long) v, Location.Null);
546 else if (t == TypeManager.uint64_type)
547 return new ULongConstant ((ulong) v, Location.Null);
548 else if (t == TypeManager.float_type)
549 return new FloatConstant ((float) v, Location.Null);
550 else if (t == TypeManager.double_type)
551 return new DoubleConstant ((double) v, Location.Null);
552 else if (t == TypeManager.string_type)
553 return new StringConstant ((string) v, Location.Null);
554 else if (t == TypeManager.short_type)
555 return new ShortConstant ((short)v, Location.Null);
556 else if (t == TypeManager.ushort_type)
557 return new UShortConstant ((ushort)v, Location.Null);
558 else if (t == TypeManager.sbyte_type)
559 return new SByteConstant ((sbyte)v, Location.Null);
560 else if (t == TypeManager.byte_type)
561 return new ByteConstant ((byte)v, Location.Null);
562 else if (t == TypeManager.char_type)
563 return new CharConstant ((char)v, Location.Null);
564 else if (t == TypeManager.bool_type)
565 return new BoolConstant ((bool) v, Location.Null);
566 else if (t == TypeManager.decimal_type)
567 return new DecimalConstant ((decimal) v, Location.Null);
568 else if (TypeManager.IsEnumType (t)){
569 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
571 real_type = System.Enum.GetUnderlyingType (real_type);
573 Constant e = Constantify (v, real_type);
575 return new EnumConstant (e, t);
576 } else if (v == null && !TypeManager.IsValueType (t))
577 return new NullLiteral (Location.Null);
579 throw new Exception ("Unknown type for constant (" + t +
584 /// Returns a fully formed expression after a MemberLookup
587 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
590 return new EventExpr ((EventInfo) mi, loc);
591 else if (mi is FieldInfo)
592 return new FieldExpr ((FieldInfo) mi, loc);
593 else if (mi is PropertyInfo)
594 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
595 else if (mi is Type){
596 return new TypeExpression ((System.Type) mi, loc);
602 protected static ArrayList almostMatchedMembers = new ArrayList (4);
605 // FIXME: Probably implement a cache for (t,name,current_access_set)?
607 // This code could use some optimizations, but we need to do some
608 // measurements. For example, we could use a delegate to `flag' when
609 // something can not any longer be a method-group (because it is something
613 // If the return value is an Array, then it is an array of
616 // If the return value is an MemberInfo, it is anything, but a Method
620 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
621 // the arguments here and have MemberLookup return only the methods that
622 // match the argument count/type, unlike we are doing now (we delay this
625 // This is so we can catch correctly attempts to invoke instance methods
626 // from a static body (scan for error 120 in ResolveSimpleName).
629 // FIXME: Potential optimization, have a static ArrayList
632 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
633 MemberTypes mt, BindingFlags bf, Location loc)
635 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
639 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
640 // `qualifier_type' or null to lookup members in the current class.
643 public static Expression MemberLookup (Type container_type,
644 Type qualifier_type, Type queried_type,
645 string name, MemberTypes mt,
646 BindingFlags bf, Location loc)
648 almostMatchedMembers.Clear ();
650 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
651 queried_type, mt, bf, name, almostMatchedMembers);
657 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
658 MemberInfo non_method = null;
659 ArrayList methods = new ArrayList (2);
661 foreach (MemberInfo m in mi) {
662 if (m is MethodBase) {
667 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 && is_interface) {
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 if (methods.Count == 0)
691 return new MethodGroupExpr (mi, loc);
693 return new MethodGroupExpr (methods, loc);
696 if (mi [0] is MethodBase)
697 return new MethodGroupExpr (mi, loc);
699 return ExprClassFromMemberInfo (container_type, mi [0], loc);
702 public const MemberTypes AllMemberTypes =
703 MemberTypes.Constructor |
707 MemberTypes.NestedType |
708 MemberTypes.Property;
710 public const BindingFlags AllBindingFlags =
711 BindingFlags.Public |
712 BindingFlags.Static |
713 BindingFlags.Instance;
715 public static Expression MemberLookup (Type container_type, Type queried_type,
716 string name, Location loc)
718 return MemberLookup (container_type, null, queried_type, name,
719 AllMemberTypes, AllBindingFlags, loc);
722 public static Expression MemberLookup (Type container_type, Type qualifier_type,
723 Type queried_type, string name, Location loc)
725 return MemberLookup (container_type, qualifier_type, queried_type,
726 name, AllMemberTypes, AllBindingFlags, loc);
729 public static Expression MethodLookup (EmitContext ec, Type queried_type,
730 string name, Location loc)
732 return MemberLookup (ec.ContainerType, null, queried_type, name,
733 MemberTypes.Method, AllBindingFlags, loc);
737 /// This is a wrapper for MemberLookup that is not used to "probe", but
738 /// to find a final definition. If the final definition is not found, we
739 /// look for private members and display a useful debugging message if we
742 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
743 Type queried_type, string name, Location loc)
745 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
746 AllMemberTypes, AllBindingFlags, loc);
749 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
750 Type queried_type, string name,
751 MemberTypes mt, BindingFlags bf,
756 int errors = Report.Errors;
758 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
760 if (e == null && errors == Report.Errors)
761 // No errors were reported by MemberLookup, but there was an error.
762 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
767 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
768 Type queried_type, string name,
769 string class_name, bool complain_if_none_found,
772 if (almostMatchedMembers.Count != 0) {
773 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
774 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
775 for (int j = 0; j < i; ++j) {
776 if (m == almostMatchedMembers [j]) {
784 Type declaring_type = m.DeclaringType;
786 Report.SymbolRelatedToPreviousError (m);
787 if (qualifier_type == null) {
788 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
789 TypeManager.CSharpName (m.DeclaringType),
790 TypeManager.CSharpName (container_type));
792 } else if (qualifier_type != container_type &&
793 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
794 // Although a derived class can access protected members of
795 // its base class it cannot do so through an instance of the
796 // base class (CS1540). If the qualifier_type is a base of the
797 // ec.ContainerType and the lookup succeeds with the latter one,
798 // then we are in this situation.
799 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
801 Report.SymbolRelatedToPreviousError (m);
802 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
805 almostMatchedMembers.Clear ();
809 MemberInfo[] lookup = null;
810 if (queried_type == null) {
811 class_name = "global::";
813 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
814 AllMemberTypes, AllBindingFlags |
815 BindingFlags.NonPublic, name, null);
818 if (lookup == null) {
819 if (!complain_if_none_found)
822 if (class_name != null)
823 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
826 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
830 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
831 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
832 if (name == ".ctor" && ml.Count == 0)
834 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
838 Report.SymbolRelatedToPreviousError (lookup [0]);
839 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
843 /// Returns an expression that can be used to invoke operator true
844 /// on the expression if it exists.
846 static public StaticCallExpr GetOperatorTrue (EmitContext ec, Expression e, Location loc)
848 return GetOperatorTrueOrFalse (ec, e, true, loc);
852 /// Returns an expression that can be used to invoke operator false
853 /// on the expression if it exists.
855 static public StaticCallExpr GetOperatorFalse (EmitContext ec, Expression e, Location loc)
857 return GetOperatorTrueOrFalse (ec, e, false, loc);
860 static StaticCallExpr GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
863 Expression operator_group;
865 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
866 if (operator_group == null)
869 ArrayList arguments = new ArrayList ();
870 arguments.Add (new Argument (e, Argument.AType.Expression));
871 method = Invocation.OverloadResolve (
872 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
877 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
881 /// Resolves the expression `e' into a boolean expression: either through
882 /// an implicit conversion, or through an `operator true' invocation
884 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
890 if (e.Type == TypeManager.bool_type)
893 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
895 if (converted != null)
899 // If no implicit conversion to bool exists, try using `operator true'
901 converted = Expression.GetOperatorTrue (ec, e, loc);
902 if (converted == null){
903 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
909 public virtual string ExprClassName
913 case ExprClass.Invalid:
915 case ExprClass.Value:
917 case ExprClass.Variable:
919 case ExprClass.Namespace:
923 case ExprClass.MethodGroup:
924 return "method group";
925 case ExprClass.PropertyAccess:
926 return "property access";
927 case ExprClass.EventAccess:
928 return "event access";
929 case ExprClass.IndexerAccess:
930 return "indexer access";
931 case ExprClass.Nothing:
934 throw new Exception ("Should not happen");
939 /// Reports that we were expecting `expr' to be of class `expected'
941 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
943 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
946 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
948 string name = GetSignatureForError ();
950 name = ds.GetSignatureForError () + '.' + name;
952 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
953 name, was, expected);
956 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
958 string [] valid = new string [4];
961 if ((flags & ResolveFlags.VariableOrValue) != 0) {
962 valid [count++] = "variable";
963 valid [count++] = "value";
966 if ((flags & ResolveFlags.Type) != 0)
967 valid [count++] = "type";
969 if ((flags & ResolveFlags.MethodGroup) != 0)
970 valid [count++] = "method group";
973 valid [count++] = "unknown";
975 StringBuilder sb = new StringBuilder (valid [0]);
976 for (int i = 1; i < count - 1; i++) {
978 sb.Append (valid [i]);
981 sb.Append ("' or `");
982 sb.Append (valid [count - 1]);
985 Report.Error (119, loc,
986 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
989 public static void UnsafeError (Location loc)
991 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
995 // Load the object from the pointer.
997 public static void LoadFromPtr (ILGenerator ig, Type t)
999 if (t == TypeManager.int32_type)
1000 ig.Emit (OpCodes.Ldind_I4);
1001 else if (t == TypeManager.uint32_type)
1002 ig.Emit (OpCodes.Ldind_U4);
1003 else if (t == TypeManager.short_type)
1004 ig.Emit (OpCodes.Ldind_I2);
1005 else if (t == TypeManager.ushort_type)
1006 ig.Emit (OpCodes.Ldind_U2);
1007 else if (t == TypeManager.char_type)
1008 ig.Emit (OpCodes.Ldind_U2);
1009 else if (t == TypeManager.byte_type)
1010 ig.Emit (OpCodes.Ldind_U1);
1011 else if (t == TypeManager.sbyte_type)
1012 ig.Emit (OpCodes.Ldind_I1);
1013 else if (t == TypeManager.uint64_type)
1014 ig.Emit (OpCodes.Ldind_I8);
1015 else if (t == TypeManager.int64_type)
1016 ig.Emit (OpCodes.Ldind_I8);
1017 else if (t == TypeManager.float_type)
1018 ig.Emit (OpCodes.Ldind_R4);
1019 else if (t == TypeManager.double_type)
1020 ig.Emit (OpCodes.Ldind_R8);
1021 else if (t == TypeManager.bool_type)
1022 ig.Emit (OpCodes.Ldind_I1);
1023 else if (t == TypeManager.intptr_type)
1024 ig.Emit (OpCodes.Ldind_I);
1025 else if (TypeManager.IsEnumType (t)) {
1026 if (t == TypeManager.enum_type)
1027 ig.Emit (OpCodes.Ldind_Ref);
1029 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1030 } else if (t.IsValueType)
1031 ig.Emit (OpCodes.Ldobj, t);
1032 else if (t.IsPointer)
1033 ig.Emit (OpCodes.Ldind_I);
1035 ig.Emit (OpCodes.Ldind_Ref);
1039 // The stack contains the pointer and the value of type `type'
1041 public static void StoreFromPtr (ILGenerator ig, Type type)
1043 if (TypeManager.IsEnumType (type))
1044 type = TypeManager.EnumToUnderlying (type);
1045 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1046 ig.Emit (OpCodes.Stind_I4);
1047 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1048 ig.Emit (OpCodes.Stind_I8);
1049 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1050 type == TypeManager.ushort_type)
1051 ig.Emit (OpCodes.Stind_I2);
1052 else if (type == TypeManager.float_type)
1053 ig.Emit (OpCodes.Stind_R4);
1054 else if (type == TypeManager.double_type)
1055 ig.Emit (OpCodes.Stind_R8);
1056 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1057 type == TypeManager.bool_type)
1058 ig.Emit (OpCodes.Stind_I1);
1059 else if (type == TypeManager.intptr_type)
1060 ig.Emit (OpCodes.Stind_I);
1061 else if (type.IsValueType)
1062 ig.Emit (OpCodes.Stobj, type);
1064 ig.Emit (OpCodes.Stind_Ref);
1068 // Returns the size of type `t' if known, otherwise, 0
1070 public static int GetTypeSize (Type t)
1072 t = TypeManager.TypeToCoreType (t);
1073 if (t == TypeManager.int32_type ||
1074 t == TypeManager.uint32_type ||
1075 t == TypeManager.float_type)
1077 else if (t == TypeManager.int64_type ||
1078 t == TypeManager.uint64_type ||
1079 t == TypeManager.double_type)
1081 else if (t == TypeManager.byte_type ||
1082 t == TypeManager.sbyte_type ||
1083 t == TypeManager.bool_type)
1085 else if (t == TypeManager.short_type ||
1086 t == TypeManager.char_type ||
1087 t == TypeManager.ushort_type)
1089 else if (t == TypeManager.decimal_type)
1095 public static void Error_NegativeArrayIndex (Location loc)
1097 Report.Error (248, loc, "Cannot create an array with a negative size");
1100 protected void Error_CannotCallAbstractBase (string name)
1102 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1106 // Converts `source' to an int, uint, long or ulong.
1108 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1112 using (ec.With (EmitContext.Flags.CheckState, true)) {
1113 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1115 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1117 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1119 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1121 if (target == null) {
1122 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1128 // Only positive constants are allowed at compile time
1130 if (target is Constant){
1131 if (target is IntConstant){
1132 if (((IntConstant) target).Value < 0){
1133 Error_NegativeArrayIndex (loc);
1138 if (target is LongConstant){
1139 if (((LongConstant) target).Value < 0){
1140 Error_NegativeArrayIndex (loc);
1153 /// This is just a base class for expressions that can
1154 /// appear on statements (invocations, object creation,
1155 /// assignments, post/pre increment and decrement). The idea
1156 /// being that they would support an extra Emition interface that
1157 /// does not leave a result on the stack.
1159 public abstract class ExpressionStatement : Expression {
1161 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1163 Expression e = Resolve (ec);
1167 ExpressionStatement es = e as ExpressionStatement;
1169 Error (201, "Only assignment, call, increment, decrement and new object " +
1170 "expressions can be used as a statement");
1176 /// Requests the expression to be emitted in a `statement'
1177 /// context. This means that no new value is left on the
1178 /// stack after invoking this method (constrasted with
1179 /// Emit that will always leave a value on the stack).
1181 public abstract void EmitStatement (EmitContext ec);
1185 /// This kind of cast is used to encapsulate the child
1186 /// whose type is child.Type into an expression that is
1187 /// reported to return "return_type". This is used to encapsulate
1188 /// expressions which have compatible types, but need to be dealt
1189 /// at higher levels with.
1191 /// For example, a "byte" expression could be encapsulated in one
1192 /// of these as an "unsigned int". The type for the expression
1193 /// would be "unsigned int".
1196 public class EmptyCast : Expression {
1197 protected readonly Expression child;
1199 public EmptyCast (Expression child, Type return_type)
1201 eclass = child.eclass;
1202 loc = child.Location;
1207 public override Expression DoResolve (EmitContext ec)
1209 // This should never be invoked, we are born in fully
1210 // initialized state.
1215 public override void Emit (EmitContext ec)
1220 public override bool GetAttributableValue (Type valueType, out object value)
1222 return child.GetAttributableValue (valueType, out value);
1227 /// This is a numeric cast to a Decimal
1229 public class CastToDecimal : EmptyCast {
1231 MethodInfo conversion_operator;
1233 public CastToDecimal (Expression child)
1234 : this (child, false)
1238 public CastToDecimal (Expression child, bool find_explicit)
1239 : base (child, TypeManager.decimal_type)
1241 conversion_operator = GetConversionOperator (find_explicit);
1243 if (conversion_operator == null)
1244 throw new InternalErrorException ("Outer conversion routine is out of sync");
1247 // Returns the implicit operator that converts from
1248 // 'child.Type' to System.Decimal.
1249 MethodInfo GetConversionOperator (bool find_explicit)
1251 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1253 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1254 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1256 foreach (MethodInfo oper in mi) {
1257 ParameterData pd = TypeManager.GetParameterData (oper);
1259 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1265 public override void Emit (EmitContext ec)
1267 ILGenerator ig = ec.ig;
1270 ig.Emit (OpCodes.Call, conversion_operator);
1275 /// This is an explicit numeric cast from a Decimal
1277 public class CastFromDecimal : EmptyCast
1279 static IDictionary operators;
1281 public CastFromDecimal (Expression child, Type return_type)
1282 : base (child, return_type)
1284 if (child.Type != TypeManager.decimal_type)
1285 throw new InternalErrorException (
1286 "The expected type is Decimal, instead it is " + child.Type.FullName);
1289 // Returns the explicit operator that converts from an
1290 // express of type System.Decimal to 'type'.
1291 public Expression Resolve ()
1293 if (operators == null) {
1294 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1295 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1296 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1298 operators = new System.Collections.Specialized.HybridDictionary ();
1299 foreach (MethodInfo oper in all_oper) {
1300 ParameterData pd = TypeManager.GetParameterData (oper);
1301 if (pd.ParameterType (0) == TypeManager.decimal_type)
1302 operators.Add (oper.ReturnType, oper);
1306 return operators.Contains (type) ? this : null;
1309 public override void Emit (EmitContext ec)
1311 ILGenerator ig = ec.ig;
1314 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1319 // We need to special case this since an empty cast of
1320 // a NullLiteral is still a Constant
1322 public class NullCast : Constant {
1323 public Constant child;
1325 public NullCast (Constant child, Type return_type):
1326 base (Location.Null)
1328 eclass = child.eclass;
1333 override public string AsString ()
1338 public override object GetValue ()
1343 public override Expression DoResolve (EmitContext ec)
1345 // This should never be invoked, we are born in fully
1346 // initialized state.
1351 public override void Emit (EmitContext ec)
1356 public override Constant Increment ()
1358 throw new NotSupportedException ();
1361 public override bool IsDefaultValue {
1367 public override bool IsNegative {
1373 public override Constant Reduce (bool inCheckedContext, Type target_type)
1375 if (type == target_type)
1376 return child.Reduce (inCheckedContext, target_type);
1385 /// This class is used to wrap literals which belong inside Enums
1387 public class EnumConstant : Constant {
1388 public Constant Child;
1390 public EnumConstant (Constant child, Type enum_type):
1391 base (child.Location)
1393 eclass = child.eclass;
1398 public override Expression DoResolve (EmitContext ec)
1400 // This should never be invoked, we are born in fully
1401 // initialized state.
1406 public override void Emit (EmitContext ec)
1411 public override bool GetAttributableValue (Type valueType, out object value)
1413 value = GetTypedValue ();
1417 public override string GetSignatureForError()
1419 return TypeManager.CSharpName (Type);
1422 public override object GetValue ()
1424 return Child.GetValue ();
1427 public override object GetTypedValue ()
1429 // FIXME: runtime is not ready to work with just emited enums
1430 if (!RootContext.StdLib) {
1431 return Child.GetValue ();
1434 return System.Enum.ToObject (type, Child.GetValue ());
1437 public override string AsString ()
1439 return Child.AsString ();
1442 public override DoubleConstant ConvertToDouble ()
1444 return Child.ConvertToDouble ();
1447 public override FloatConstant ConvertToFloat ()
1449 return Child.ConvertToFloat ();
1452 public override ULongConstant ConvertToULong ()
1454 return Child.ConvertToULong ();
1457 public override LongConstant ConvertToLong ()
1459 return Child.ConvertToLong ();
1462 public override UIntConstant ConvertToUInt ()
1464 return Child.ConvertToUInt ();
1467 public override IntConstant ConvertToInt ()
1469 return Child.ConvertToInt ();
1472 public override Constant Increment()
1474 return new EnumConstant (Child.Increment (), type);
1477 public override bool IsDefaultValue {
1479 return Child.IsDefaultValue;
1483 public override bool IsZeroInteger {
1484 get { return Child.IsZeroInteger; }
1487 public override bool IsNegative {
1489 return Child.IsNegative;
1493 public override Constant Reduce(bool inCheckedContext, Type target_type)
1495 if (Child.Type == target_type)
1498 return Child.Reduce (inCheckedContext, target_type);
1501 public override Constant ToType (Type type, Location loc)
1504 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1505 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1508 if (type.UnderlyingSystemType != Child.Type)
1509 Child = Child.ToType (type.UnderlyingSystemType, loc);
1513 if (!Convert.ImplicitStandardConversionExists (this, type)){
1514 Error_ValueCannotBeConverted (loc, type, false);
1518 return Child.ToType (type, loc);
1524 /// This kind of cast is used to encapsulate Value Types in objects.
1526 /// The effect of it is to box the value type emitted by the previous
1529 public class BoxedCast : EmptyCast {
1531 public BoxedCast (Expression expr, Type target_type)
1532 : base (expr, target_type)
1534 eclass = ExprClass.Value;
1537 public override Expression DoResolve (EmitContext ec)
1539 // This should never be invoked, we are born in fully
1540 // initialized state.
1545 public override void Emit (EmitContext ec)
1549 ec.ig.Emit (OpCodes.Box, child.Type);
1553 public class UnboxCast : EmptyCast {
1554 public UnboxCast (Expression expr, Type return_type)
1555 : base (expr, return_type)
1559 public override Expression DoResolve (EmitContext ec)
1561 // This should never be invoked, we are born in fully
1562 // initialized state.
1567 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1569 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1570 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1571 return base.DoResolveLValue (ec, right_side);
1574 public override void Emit (EmitContext ec)
1577 ILGenerator ig = ec.ig;
1580 ig.Emit (OpCodes.Unbox, t);
1582 LoadFromPtr (ig, t);
1587 /// This is used to perform explicit numeric conversions.
1589 /// Explicit numeric conversions might trigger exceptions in a checked
1590 /// context, so they should generate the conv.ovf opcodes instead of
1593 public class ConvCast : EmptyCast {
1594 public enum Mode : byte {
1595 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1597 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1598 U2_I1, U2_U1, U2_I2, U2_CH,
1599 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1600 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1601 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1602 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1603 CH_I1, CH_U1, CH_I2,
1604 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1605 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1610 public ConvCast (Expression child, Type return_type, Mode m)
1611 : base (child, return_type)
1616 public override Expression DoResolve (EmitContext ec)
1618 // This should never be invoked, we are born in fully
1619 // initialized state.
1624 public override string ToString ()
1626 return String.Format ("ConvCast ({0}, {1})", mode, child);
1629 public override void Emit (EmitContext ec)
1631 ILGenerator ig = ec.ig;
1637 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1638 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1639 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1640 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1641 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1643 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1644 case Mode.U1_CH: /* nothing */ break;
1646 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1647 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1648 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1649 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1650 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1651 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1653 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1654 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1655 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1656 case Mode.U2_CH: /* nothing */ break;
1658 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1659 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1660 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1661 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1662 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1663 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1664 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1666 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1667 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1668 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1669 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1670 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1671 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1673 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1674 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1675 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1676 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1677 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1678 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1679 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1680 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1682 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1683 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1684 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1685 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1686 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1687 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1688 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1689 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1691 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1692 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1693 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1695 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1696 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1697 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1698 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1699 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1700 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1701 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1702 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1703 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1705 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1706 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1707 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1708 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1709 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1710 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1711 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1712 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1713 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1714 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1718 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1719 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1720 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1721 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1722 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1724 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1725 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1727 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1728 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1729 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1730 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1731 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1732 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1734 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1735 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1736 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1737 case Mode.U2_CH: /* nothing */ break;
1739 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1740 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1741 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1742 case Mode.I4_U4: /* nothing */ break;
1743 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1744 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1745 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1747 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1748 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1749 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1750 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1751 case Mode.U4_I4: /* nothing */ break;
1752 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1754 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1755 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1756 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1757 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1758 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1759 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1760 case Mode.I8_U8: /* nothing */ break;
1761 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1763 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1764 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1765 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1766 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1767 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1768 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1769 case Mode.U8_I8: /* nothing */ break;
1770 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1772 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1773 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1774 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1776 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1777 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1778 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1779 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1780 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1781 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1782 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1783 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1784 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1786 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1787 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1788 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1789 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1790 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1791 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1792 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1793 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1794 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1795 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1801 public class OpcodeCast : EmptyCast {
1805 public OpcodeCast (Expression child, Type return_type, OpCode op)
1806 : base (child, return_type)
1810 second_valid = false;
1813 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1814 : base (child, return_type)
1819 second_valid = true;
1822 public override Expression DoResolve (EmitContext ec)
1824 // This should never be invoked, we are born in fully
1825 // initialized state.
1830 public override void Emit (EmitContext ec)
1841 /// This kind of cast is used to encapsulate a child and cast it
1842 /// to the class requested
1844 public class ClassCast : EmptyCast {
1845 public ClassCast (Expression child, Type return_type)
1846 : base (child, return_type)
1851 public override Expression DoResolve (EmitContext ec)
1853 // This should never be invoked, we are born in fully
1854 // initialized state.
1859 public override void Emit (EmitContext ec)
1863 ec.ig.Emit (OpCodes.Castclass, type);
1869 /// SimpleName expressions are formed of a single word and only happen at the beginning
1870 /// of a dotted-name.
1872 public class SimpleName : Expression {
1876 public SimpleName (string name, Location l)
1882 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1884 if (ec.IsFieldInitializer)
1885 Report.Error (236, l,
1886 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1890 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1894 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1896 return resolved_to != null && resolved_to.Type != null &&
1897 resolved_to.Type.Name == Name &&
1898 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1901 public override Expression DoResolve (EmitContext ec)
1903 return SimpleNameResolve (ec, null, false);
1906 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1908 return SimpleNameResolve (ec, right_side, false);
1912 public Expression DoResolve (EmitContext ec, bool intermediate)
1914 return SimpleNameResolve (ec, null, intermediate);
1917 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
1919 int errors = Report.Errors;
1920 FullNamedExpression fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
1924 if (silent || errors != Report.Errors)
1927 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
1929 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
1933 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
1934 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
1935 foreach (Assembly a in RootNamespace.Global.Assemblies) {
1936 Type type = a.GetType (fullname);
1938 Report.SymbolRelatedToPreviousError (type);
1939 Expression.ErrorIsInaccesible (loc, fullname);
1944 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
1948 // TODO: I am still not convinced about this. If someone else will need it
1949 // implement this as virtual property in MemberCore hierarchy
1950 string GetMemberType (MemberCore mc)
1952 if (mc is PropertyBase)
1956 if (mc is FieldBase)
1958 if (mc is MethodCore)
1960 if (mc is EnumMember)
1966 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
1972 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
1976 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
1983 /// 7.5.2: Simple Names.
1985 /// Local Variables and Parameters are handled at
1986 /// parse time, so they never occur as SimpleNames.
1988 /// The `intermediate' flag is used by MemberAccess only
1989 /// and it is used to inform us that it is ok for us to
1990 /// avoid the static check, because MemberAccess might end
1991 /// up resolving the Name as a Type name and the access as
1992 /// a static type access.
1994 /// ie: Type Type; .... { Type.GetType (""); }
1996 /// Type is both an instance variable and a Type; Type.GetType
1997 /// is the static method not an instance method of type.
1999 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2001 Expression e = null;
2004 // Stage 1: Performed by the parser (binding to locals or parameters).
2006 Block current_block = ec.CurrentBlock;
2007 if (current_block != null){
2008 LocalInfo vi = current_block.GetLocalInfo (Name);
2010 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2011 if (right_side != null) {
2012 return var.ResolveLValue (ec, right_side, loc);
2014 ResolveFlags rf = ResolveFlags.VariableOrValue;
2016 rf |= ResolveFlags.DisableFlowAnalysis;
2017 return var.Resolve (ec, rf);
2021 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2023 if (right_side != null)
2024 return pref.ResolveLValue (ec, right_side, loc);
2026 return pref.Resolve (ec);
2031 // Stage 2: Lookup members
2034 DeclSpace lookup_ds = ec.DeclContainer;
2035 Type almost_matched_type = null;
2036 ArrayList almost_matched = null;
2038 if (lookup_ds.TypeBuilder == null)
2041 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2045 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2046 almost_matched_type = lookup_ds.TypeBuilder;
2047 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2050 lookup_ds =lookup_ds.Parent;
2051 } while (lookup_ds != null);
2053 if (e == null && ec.ContainerType != null)
2054 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2057 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2058 almost_matched_type = ec.ContainerType;
2059 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2061 e = ResolveAsTypeStep (ec, true);
2065 if (almost_matched != null)
2066 almostMatchedMembers = almost_matched;
2067 if (almost_matched_type == null)
2068 almost_matched_type = ec.ContainerType;
2069 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2076 if (e is MemberExpr) {
2077 MemberExpr me = (MemberExpr) e;
2080 if (me.IsInstance) {
2081 if (ec.IsStatic || ec.IsFieldInitializer) {
2083 // Note that an MemberExpr can be both IsInstance and IsStatic.
2084 // An unresolved MethodGroupExpr can contain both kinds of methods
2085 // and each predicate is true if the MethodGroupExpr contains
2086 // at least one of that kind of method.
2090 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2091 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2092 return EmptyExpression.Null;
2096 // Pass the buck to MemberAccess and Invocation.
2098 left = EmptyExpression.Null;
2100 left = ec.GetThis (loc);
2103 left = new TypeExpression (ec.ContainerType, loc);
2106 e = me.ResolveMemberAccess (ec, left, loc, null);
2110 me = e as MemberExpr;
2115 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2116 me.InstanceExpression.Type != me.DeclaringType &&
2117 !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType) &&
2118 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2119 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2120 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2124 return (right_side != null)
2125 ? me.DoResolveLValue (ec, right_side)
2126 : me.DoResolve (ec);
2132 public override void Emit (EmitContext ec)
2135 // If this is ever reached, then we failed to
2136 // find the name as a namespace
2139 Error (103, "The name `" + Name +
2140 "' does not exist in the class `" +
2141 ec.DeclContainer.Name + "'");
2144 public override string ToString ()
2149 public override string GetSignatureForError ()
2156 /// Represents a namespace or a type. The name of the class was inspired by
2157 /// section 10.8.1 (Fully Qualified Names).
2159 public abstract class FullNamedExpression : Expression {
2160 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2165 public abstract string FullName {
2171 /// Expression that evaluates to a type
2173 public abstract class TypeExpr : FullNamedExpression {
2174 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2176 TypeExpr t = DoResolveAsTypeStep (ec);
2180 eclass = ExprClass.Type;
2184 override public Expression DoResolve (EmitContext ec)
2186 return ResolveAsTypeTerminal (ec, false);
2189 override public void Emit (EmitContext ec)
2191 throw new Exception ("Should never be called");
2194 public virtual bool CheckAccessLevel (DeclSpace ds)
2196 return ds.CheckAccessLevel (Type);
2199 public virtual bool AsAccessible (DeclSpace ds, int flags)
2201 return ds.AsAccessible (Type, flags);
2204 public virtual bool IsClass {
2205 get { return Type.IsClass; }
2208 public virtual bool IsValueType {
2209 get { return Type.IsValueType; }
2212 public virtual bool IsInterface {
2213 get { return Type.IsInterface; }
2216 public virtual bool IsSealed {
2217 get { return Type.IsSealed; }
2220 public virtual bool CanInheritFrom ()
2222 if (Type == TypeManager.enum_type ||
2223 (Type == TypeManager.value_type && RootContext.StdLib) ||
2224 Type == TypeManager.multicast_delegate_type ||
2225 Type == TypeManager.delegate_type ||
2226 Type == TypeManager.array_type)
2232 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2234 public abstract string Name {
2238 public override bool Equals (object obj)
2240 TypeExpr tobj = obj as TypeExpr;
2244 return Type == tobj.Type;
2247 public override int GetHashCode ()
2249 return Type.GetHashCode ();
2252 public override string ToString ()
2259 /// Fully resolved Expression that already evaluated to a type
2261 public class TypeExpression : TypeExpr {
2262 public TypeExpression (Type t, Location l)
2265 eclass = ExprClass.Type;
2269 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2274 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2279 public override string Name {
2280 get { return Type.ToString (); }
2283 public override string FullName {
2284 get { return Type.FullName; }
2289 /// Used to create types from a fully qualified name. These are just used
2290 /// by the parser to setup the core types. A TypeLookupExpression is always
2291 /// classified as a type.
2293 public sealed class TypeLookupExpression : TypeExpr {
2294 readonly string name;
2296 public TypeLookupExpression (string name)
2299 eclass = ExprClass.Type;
2302 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2304 // It's null for corlib compilation only
2306 return DoResolveAsTypeStep (ec);
2311 static readonly char [] dot_array = { '.' };
2312 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2314 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2316 string lookup_name = name;
2317 int pos = name.IndexOf ('.');
2319 rest = name.Substring (pos + 1);
2320 lookup_name = name.Substring (0, pos);
2323 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2325 if (resolved != null && rest != null) {
2326 // Now handle the rest of the the name.
2327 string [] elements = rest.Split (dot_array);
2329 int count = elements.Length;
2331 while (i < count && resolved != null && resolved is Namespace) {
2332 Namespace ns = resolved as Namespace;
2333 element = elements [i++];
2334 lookup_name += "." + element;
2335 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2338 if (resolved != null && resolved is TypeExpr) {
2339 Type t = ((TypeExpr) resolved).Type;
2341 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2343 lookup_name = t.FullName;
2350 t = TypeManager.GetNestedType (t, elements [i++]);
2355 if (resolved == null) {
2356 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2360 if (!(resolved is TypeExpr)) {
2361 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2365 type = resolved.Type;
2369 public override string Name {
2370 get { return name; }
2373 public override string FullName {
2374 get { return name; }
2378 public class TypeAliasExpression : TypeExpr {
2381 public TypeAliasExpression (TypeExpr texpr, Location l)
2384 loc = texpr.Location;
2386 eclass = ExprClass.Type;
2389 public override string Name {
2390 get { return texpr.Name; }
2393 public override string FullName {
2394 get { return texpr.FullName; }
2397 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2402 public override bool CheckAccessLevel (DeclSpace ds)
2404 return texpr.CheckAccessLevel (ds);
2407 public override bool AsAccessible (DeclSpace ds, int flags)
2409 return texpr.AsAccessible (ds, flags);
2412 public override bool IsClass {
2413 get { return texpr.IsClass; }
2416 public override bool IsValueType {
2417 get { return texpr.IsValueType; }
2420 public override bool IsInterface {
2421 get { return texpr.IsInterface; }
2424 public override bool IsSealed {
2425 get { return texpr.IsSealed; }
2430 /// This class denotes an expression which evaluates to a member
2431 /// of a struct or a class.
2433 public abstract class MemberExpr : Expression
2436 /// The name of this member.
2438 public abstract string Name {
2443 /// Whether this is an instance member.
2445 public abstract bool IsInstance {
2450 /// Whether this is a static member.
2452 public abstract bool IsStatic {
2457 /// The type which declares this member.
2459 public abstract Type DeclaringType {
2464 /// The instance expression associated with this member, if it's a
2465 /// non-static member.
2467 public Expression InstanceExpression;
2469 public static void error176 (Location loc, string name)
2471 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2472 "with an instance reference, qualify it with a type name instead", name);
2475 // TODO: possible optimalization
2476 // Cache resolved constant result in FieldBuilder <-> expression map
2477 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2478 SimpleName original)
2482 // original == null || original.Resolve (...) ==> left
2485 if (left is TypeExpr) {
2487 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2495 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2498 error176 (loc, GetSignatureForError ());
2502 InstanceExpression = left;
2507 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2512 if (InstanceExpression == EmptyExpression.Null) {
2513 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2517 if (InstanceExpression.Type.IsValueType) {
2518 if (InstanceExpression is IMemoryLocation) {
2519 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2521 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2522 InstanceExpression.Emit (ec);
2524 t.AddressOf (ec, AddressOp.Store);
2527 InstanceExpression.Emit (ec);
2529 if (prepare_for_load)
2530 ec.ig.Emit (OpCodes.Dup);
2535 /// MethodGroup Expression.
2537 /// This is a fully resolved expression that evaluates to a type
2539 public class MethodGroupExpr : MemberExpr {
2540 public MethodBase [] Methods;
2541 bool identical_type_name = false;
2544 public MethodGroupExpr (MemberInfo [] mi, Location l)
2546 Methods = new MethodBase [mi.Length];
2547 mi.CopyTo (Methods, 0);
2548 eclass = ExprClass.MethodGroup;
2549 type = TypeManager.object_type;
2553 public MethodGroupExpr (ArrayList list, Location l)
2555 Methods = new MethodBase [list.Count];
2558 list.CopyTo (Methods, 0);
2560 foreach (MemberInfo m in list){
2561 if (!(m is MethodBase)){
2562 Console.WriteLine ("Name " + m.Name);
2563 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2570 eclass = ExprClass.MethodGroup;
2571 type = TypeManager.object_type;
2574 public override Type DeclaringType {
2577 // The methods are arranged in this order:
2578 // derived type -> base type
2580 return Methods [0].DeclaringType;
2584 public bool IdenticalTypeName {
2586 return identical_type_name;
2590 identical_type_name = value;
2594 public bool IsBase {
2603 public override string GetSignatureForError ()
2605 return TypeManager.CSharpSignature (Methods [0]);
2608 public override string Name {
2610 return Methods [0].Name;
2614 public override bool IsInstance {
2616 foreach (MethodBase mb in Methods)
2624 public override bool IsStatic {
2626 foreach (MethodBase mb in Methods)
2634 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2635 SimpleName original)
2637 if (!(left is TypeExpr) &&
2638 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2639 IdenticalTypeName = true;
2641 return base.ResolveMemberAccess (ec, left, loc, original);
2644 override public Expression DoResolve (EmitContext ec)
2647 InstanceExpression = null;
2649 if (InstanceExpression != null) {
2650 InstanceExpression = InstanceExpression.DoResolve (ec);
2651 if (InstanceExpression == null)
2658 public void ReportUsageError ()
2660 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2661 Name + "()' is referenced without parentheses");
2664 override public void Emit (EmitContext ec)
2666 ReportUsageError ();
2669 bool RemoveMethods (bool keep_static)
2671 ArrayList smethods = new ArrayList ();
2673 foreach (MethodBase mb in Methods){
2674 if (mb.IsStatic == keep_static)
2678 if (smethods.Count == 0)
2681 Methods = new MethodBase [smethods.Count];
2682 smethods.CopyTo (Methods, 0);
2688 /// Removes any instance methods from the MethodGroup, returns
2689 /// false if the resulting set is empty.
2691 public bool RemoveInstanceMethods ()
2693 return RemoveMethods (true);
2697 /// Removes any static methods from the MethodGroup, returns
2698 /// false if the resulting set is empty.
2700 public bool RemoveStaticMethods ()
2702 return RemoveMethods (false);
2707 /// Fully resolved expression that evaluates to a Field
2709 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2710 public readonly FieldInfo FieldInfo;
2711 VariableInfo variable_info;
2713 LocalTemporary temp;
2715 bool in_initializer;
2717 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2720 this.in_initializer = in_initializer;
2723 public FieldExpr (FieldInfo fi, Location l)
2726 eclass = ExprClass.Variable;
2727 type = fi.FieldType;
2731 public override string Name {
2733 return FieldInfo.Name;
2737 public override bool IsInstance {
2739 return !FieldInfo.IsStatic;
2743 public override bool IsStatic {
2745 return FieldInfo.IsStatic;
2749 public override Type DeclaringType {
2751 return FieldInfo.DeclaringType;
2755 public override string GetSignatureForError ()
2757 return TypeManager.GetFullNameSignature (FieldInfo);
2760 public VariableInfo VariableInfo {
2762 return variable_info;
2766 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2767 SimpleName original)
2769 Type t = FieldInfo.FieldType;
2771 if (FieldInfo.IsLiteral || (FieldInfo.IsInitOnly && t == TypeManager.decimal_type)) {
2772 IConstant ic = TypeManager.GetConstant (FieldInfo);
2774 if (FieldInfo.IsLiteral) {
2775 ic = new ExternalConstant (FieldInfo);
2777 ic = ExternalConstant.CreateDecimal (FieldInfo);
2779 return base.ResolveMemberAccess (ec, left, loc, original);
2782 TypeManager.RegisterConstant (FieldInfo, ic);
2785 bool left_is_type = left is TypeExpr;
2786 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
2787 Report.SymbolRelatedToPreviousError (FieldInfo);
2788 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
2792 if (ic.ResolveValue ()) {
2793 if (!ec.IsInObsoleteScope)
2794 ic.CheckObsoleteness (loc);
2800 if (t.IsPointer && !ec.InUnsafe) {
2805 return base.ResolveMemberAccess (ec, left, loc, original);
2808 override public Expression DoResolve (EmitContext ec)
2810 return DoResolve (ec, false, false);
2813 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
2815 if (!FieldInfo.IsStatic){
2816 if (InstanceExpression == null){
2818 // This can happen when referencing an instance field using
2819 // a fully qualified type expression: TypeName.InstanceField = xxx
2821 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2825 // Resolve the field's instance expression while flow analysis is turned
2826 // off: when accessing a field "a.b", we must check whether the field
2827 // "a.b" is initialized, not whether the whole struct "a" is initialized.
2829 if (lvalue_instance) {
2830 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
2831 Expression right_side =
2832 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
2833 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
2836 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
2837 InstanceExpression = InstanceExpression.Resolve (ec, rf);
2840 if (InstanceExpression == null)
2843 InstanceExpression.CheckMarshalByRefAccess ();
2846 if (!in_initializer && !ec.IsFieldInitializer) {
2847 ObsoleteAttribute oa;
2848 FieldBase f = TypeManager.GetField (FieldInfo);
2850 if (!ec.IsInObsoleteScope)
2851 f.CheckObsoleteness (loc);
2853 // To be sure that type is external because we do not register generated fields
2854 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
2855 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
2857 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
2861 AnonymousContainer am = ec.CurrentAnonymousMethod;
2863 if (!FieldInfo.IsStatic){
2864 if (!am.IsIterator && (ec.TypeContainer is Struct)){
2865 Report.Error (1673, loc,
2866 "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",
2870 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
2871 ec.CaptureField (this);
2875 // If the instance expression is a local variable or parameter.
2876 IVariable var = InstanceExpression as IVariable;
2877 if ((var == null) || (var.VariableInfo == null))
2880 VariableInfo vi = var.VariableInfo;
2881 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
2884 variable_info = vi.GetSubStruct (FieldInfo.Name);
2888 static readonly int [] codes = {
2889 191, // instance, write access
2890 192, // instance, out access
2891 198, // static, write access
2892 199, // static, out access
2893 1648, // member of value instance, write access
2894 1649, // member of value instance, out access
2895 1650, // member of value static, write access
2896 1651 // member of value static, out access
2899 static readonly string [] msgs = {
2900 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
2901 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2902 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2903 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
2904 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
2905 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2906 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2907 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
2910 // The return value is always null. Returning a value simplifies calling code.
2911 Expression Report_AssignToReadonly (Expression right_side)
2914 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
2918 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
2920 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
2925 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
2927 IVariable var = InstanceExpression as IVariable;
2928 if ((var != null) && (var.VariableInfo != null))
2929 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
2931 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
2932 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
2934 Expression e = DoResolve (ec, lvalue_instance, out_access);
2939 FieldBase fb = TypeManager.GetField (FieldInfo);
2943 if (FieldInfo.IsInitOnly) {
2944 // InitOnly fields can only be assigned in constructors or initializers
2945 if (!ec.IsFieldInitializer && !ec.IsConstructor)
2946 return Report_AssignToReadonly (right_side);
2948 if (ec.IsConstructor) {
2949 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
2950 if (ec.ContainerType != FieldInfo.DeclaringType)
2951 return Report_AssignToReadonly (right_side);
2952 // static InitOnly fields cannot be assigned-to in an instance constructor
2953 if (IsStatic && !ec.IsStatic)
2954 return Report_AssignToReadonly (right_side);
2955 // instance constructors can't modify InitOnly fields of other instances of the same type
2956 if (!IsStatic && !(InstanceExpression is This))
2957 return Report_AssignToReadonly (right_side);
2961 if (right_side == EmptyExpression.OutAccess &&
2962 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
2963 Report.SymbolRelatedToPreviousError (DeclaringType);
2964 Report.Warning (197, 1, loc,
2965 "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",
2966 GetSignatureForError ());
2972 public override void CheckMarshalByRefAccess ()
2974 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
2975 Report.SymbolRelatedToPreviousError (DeclaringType);
2976 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",
2977 GetSignatureForError ());
2981 public bool VerifyFixed ()
2983 IVariable variable = InstanceExpression as IVariable;
2984 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
2985 // We defer the InstanceExpression check after the variable check to avoid a
2986 // separate null check on InstanceExpression.
2987 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
2990 public override int GetHashCode ()
2992 return FieldInfo.GetHashCode ();
2995 public override bool Equals (object obj)
2997 FieldExpr fe = obj as FieldExpr;
3001 if (FieldInfo != fe.FieldInfo)
3004 if (InstanceExpression == null || fe.InstanceExpression == null)
3007 return InstanceExpression.Equals (fe.InstanceExpression);
3010 public void Emit (EmitContext ec, bool leave_copy)
3012 ILGenerator ig = ec.ig;
3013 bool is_volatile = false;
3015 FieldBase f = TypeManager.GetField (FieldInfo);
3017 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3020 f.SetMemberIsUsed ();
3023 if (FieldInfo.IsStatic){
3025 ig.Emit (OpCodes.Volatile);
3027 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3030 EmitInstance (ec, false);
3033 ig.Emit (OpCodes.Volatile);
3035 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3038 ig.Emit (OpCodes.Ldflda, FieldInfo);
3039 ig.Emit (OpCodes.Ldflda, ff.Element);
3042 ig.Emit (OpCodes.Ldfld, FieldInfo);
3047 ec.ig.Emit (OpCodes.Dup);
3048 if (!FieldInfo.IsStatic) {
3049 temp = new LocalTemporary (this.Type);
3055 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3057 FieldAttributes fa = FieldInfo.Attributes;
3058 bool is_static = (fa & FieldAttributes.Static) != 0;
3059 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3060 ILGenerator ig = ec.ig;
3061 prepared = prepare_for_load;
3063 if (is_readonly && !ec.IsConstructor){
3064 Report_AssignToReadonly (source);
3068 EmitInstance (ec, prepare_for_load);
3072 ec.ig.Emit (OpCodes.Dup);
3073 if (!FieldInfo.IsStatic) {
3074 temp = new LocalTemporary (this.Type);
3079 if (FieldInfo is FieldBuilder){
3080 FieldBase f = TypeManager.GetField (FieldInfo);
3082 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3083 ig.Emit (OpCodes.Volatile);
3090 ig.Emit (OpCodes.Stsfld, FieldInfo);
3092 ig.Emit (OpCodes.Stfld, FieldInfo);
3100 public override void Emit (EmitContext ec)
3105 public void AddressOf (EmitContext ec, AddressOp mode)
3107 ILGenerator ig = ec.ig;
3109 if (FieldInfo is FieldBuilder){
3110 FieldBase f = TypeManager.GetField (FieldInfo);
3112 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3113 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3114 f.GetSignatureForError ());
3118 if ((mode & AddressOp.Store) != 0)
3120 if ((mode & AddressOp.Load) != 0)
3121 f.SetMemberIsUsed ();
3126 // Handle initonly fields specially: make a copy and then
3127 // get the address of the copy.
3130 if (FieldInfo.IsInitOnly){
3132 if (ec.IsConstructor){
3133 if (FieldInfo.IsStatic){
3145 local = ig.DeclareLocal (type);
3146 ig.Emit (OpCodes.Stloc, local);
3147 ig.Emit (OpCodes.Ldloca, local);
3152 if (FieldInfo.IsStatic){
3153 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3155 EmitInstance (ec, false);
3156 ig.Emit (OpCodes.Ldflda, FieldInfo);
3162 // A FieldExpr whose address can not be taken
3164 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3165 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3169 public new void AddressOf (EmitContext ec, AddressOp mode)
3171 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3176 /// Expression that evaluates to a Property. The Assign class
3177 /// might set the `Value' expression if we are in an assignment.
3179 /// This is not an LValue because we need to re-write the expression, we
3180 /// can not take data from the stack and store it.
3182 public class PropertyExpr : MemberExpr, IAssignMethod {
3183 public readonly PropertyInfo PropertyInfo;
3186 // This is set externally by the `BaseAccess' class
3189 MethodInfo getter, setter;
3194 LocalTemporary temp;
3197 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3199 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3202 eclass = ExprClass.PropertyAccess;
3206 type = TypeManager.TypeToCoreType (pi.PropertyType);
3208 ResolveAccessors (containerType);
3211 public override string Name {
3213 return PropertyInfo.Name;
3217 public override bool IsInstance {
3223 public override bool IsStatic {
3229 public override Type DeclaringType {
3231 return PropertyInfo.DeclaringType;
3235 public override string GetSignatureForError ()
3237 return TypeManager.GetFullNameSignature (PropertyInfo);
3240 void FindAccessors (Type invocation_type)
3242 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3243 BindingFlags.Static | BindingFlags.Instance |
3244 BindingFlags.DeclaredOnly;
3246 Type current = PropertyInfo.DeclaringType;
3247 for (; current != null; current = current.BaseType) {
3248 MemberInfo[] group = TypeManager.MemberLookup (
3249 invocation_type, invocation_type, current,
3250 MemberTypes.Property, flags, PropertyInfo.Name, null);
3255 if (group.Length != 1)
3256 // Oooops, can this ever happen ?
3259 PropertyInfo pi = (PropertyInfo) group [0];
3262 getter = pi.GetGetMethod (true);
3265 setter = pi.GetSetMethod (true);
3267 MethodInfo accessor = getter != null ? getter : setter;
3269 if (!accessor.IsVirtual)
3275 // We also perform the permission checking here, as the PropertyInfo does not
3276 // hold the information for the accessibility of its setter/getter
3278 // TODO: can use TypeManager.GetProperty to boost performance
3279 void ResolveAccessors (Type containerType)
3281 FindAccessors (containerType);
3283 if (getter != null) {
3284 IMethodData md = TypeManager.GetMethod (getter);
3286 md.SetMemberIsUsed ();
3288 AccessorTable [getter] = PropertyInfo;
3289 is_static = getter.IsStatic;
3292 if (setter != null) {
3293 IMethodData md = TypeManager.GetMethod (setter);
3295 md.SetMemberIsUsed ();
3297 AccessorTable [setter] = PropertyInfo;
3298 is_static = setter.IsStatic;
3302 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3305 InstanceExpression = null;
3309 if (InstanceExpression == null) {
3310 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3314 if (lvalue_instance)
3315 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3317 InstanceExpression = InstanceExpression.DoResolve (ec);
3318 if (InstanceExpression == null)
3321 InstanceExpression.CheckMarshalByRefAccess ();
3323 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3324 InstanceExpression.Type != ec.ContainerType &&
3325 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3326 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3327 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3334 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3336 // TODO: correctly we should compare arguments but it will lead to bigger changes
3337 if (mi is MethodBuilder) {
3338 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3342 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3344 ParameterData iparams = TypeManager.GetParameterData (mi);
3345 sig.Append (getter ? "get_" : "set_");
3347 sig.Append (iparams.GetSignatureForError ());
3349 Report.SymbolRelatedToPreviousError (mi);
3350 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3351 Name, sig.ToString ());
3354 override public Expression DoResolve (EmitContext ec)
3359 if (getter != null){
3360 if (TypeManager.GetParameterData (getter).Count != 0){
3361 Error_PropertyNotFound (getter, true);
3366 if (getter == null){
3368 // The following condition happens if the PropertyExpr was
3369 // created, but is invalid (ie, the property is inaccessible),
3370 // and we did not want to embed the knowledge about this in
3371 // the caller routine. This only avoids double error reporting.
3376 if (InstanceExpression != EmptyExpression.Null) {
3377 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3378 TypeManager.GetFullNameSignature (PropertyInfo));
3383 bool must_do_cs1540_check = false;
3384 if (getter != null &&
3385 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3386 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3387 if (pm != null && pm.HasCustomAccessModifier) {
3388 Report.SymbolRelatedToPreviousError (pm);
3389 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3390 TypeManager.CSharpSignature (getter));
3393 Report.SymbolRelatedToPreviousError (getter);
3394 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3399 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3403 // Only base will allow this invocation to happen.
3405 if (IsBase && getter.IsAbstract) {
3406 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3410 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3420 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3422 if (right_side == EmptyExpression.OutAccess) {
3423 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3424 GetSignatureForError ());
3428 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3429 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3430 GetSignatureForError ());
3434 if (setter == null){
3436 // The following condition happens if the PropertyExpr was
3437 // created, but is invalid (ie, the property is inaccessible),
3438 // and we did not want to embed the knowledge about this in
3439 // the caller routine. This only avoids double error reporting.
3443 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3444 GetSignatureForError ());
3448 if (TypeManager.GetParameterData (setter).Count != 1){
3449 Error_PropertyNotFound (setter, false);
3453 bool must_do_cs1540_check;
3454 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3455 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3456 if (pm != null && pm.HasCustomAccessModifier) {
3457 Report.SymbolRelatedToPreviousError (pm);
3458 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3459 TypeManager.CSharpSignature (setter));
3462 Report.SymbolRelatedToPreviousError (setter);
3463 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3468 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3472 // Only base will allow this invocation to happen.
3474 if (IsBase && setter.IsAbstract){
3475 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3482 public override void Emit (EmitContext ec)
3487 public void Emit (EmitContext ec, bool leave_copy)
3490 // Special case: length of single dimension array property is turned into ldlen
3492 if ((getter == TypeManager.system_int_array_get_length) ||
3493 (getter == TypeManager.int_array_get_length)){
3494 Type iet = InstanceExpression.Type;
3497 // System.Array.Length can be called, but the Type does not
3498 // support invoking GetArrayRank, so test for that case first
3500 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3502 EmitInstance (ec, false);
3503 ec.ig.Emit (OpCodes.Ldlen);
3504 ec.ig.Emit (OpCodes.Conv_I4);
3509 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3512 ec.ig.Emit (OpCodes.Dup);
3514 temp = new LocalTemporary (this.Type);
3521 // Implements the IAssignMethod interface for assignments
3523 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3525 Expression my_source = source;
3527 prepared = prepare_for_load;
3532 ec.ig.Emit (OpCodes.Dup);
3534 temp = new LocalTemporary (this.Type);
3538 } else if (leave_copy) {
3541 temp = new LocalTemporary (this.Type);
3547 ArrayList args = new ArrayList (1);
3548 args.Add (new Argument (my_source, Argument.AType.Expression));
3550 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3560 /// Fully resolved expression that evaluates to an Event
3562 public class EventExpr : MemberExpr {
3563 public readonly EventInfo EventInfo;
3566 MethodInfo add_accessor, remove_accessor;
3568 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3570 public EventExpr (EventInfo ei, Location loc)
3574 eclass = ExprClass.EventAccess;
3576 add_accessor = TypeManager.GetAddMethod (ei);
3577 remove_accessor = TypeManager.GetRemoveMethod (ei);
3578 if (add_accessor != null)
3579 AccessorTable [add_accessor] = ei;
3580 if (remove_accessor != null)
3581 AccessorTable [remove_accessor] = ei;
3583 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3586 if (EventInfo is MyEventBuilder){
3587 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3588 type = eb.EventType;
3591 type = EventInfo.EventHandlerType;
3594 public override string Name {
3596 return EventInfo.Name;
3600 public override bool IsInstance {
3606 public override bool IsStatic {
3612 public override Type DeclaringType {
3614 return EventInfo.DeclaringType;
3618 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3619 SimpleName original)
3622 // If the event is local to this class, we transform ourselves into a FieldExpr
3625 if (EventInfo.DeclaringType == ec.ContainerType ||
3626 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3627 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3630 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3633 Report.Error (-200, loc, "Internal error!!");
3637 InstanceExpression = null;
3639 return ml.ResolveMemberAccess (ec, left, loc, original);
3643 return base.ResolveMemberAccess (ec, left, loc, original);
3647 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3650 InstanceExpression = null;
3654 if (InstanceExpression == null) {
3655 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3659 InstanceExpression = InstanceExpression.DoResolve (ec);
3660 if (InstanceExpression == null)
3664 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3665 // However, in the Event case, we reported a CS0122 instead.
3667 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3668 InstanceExpression.Type != ec.ContainerType &&
3669 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3670 Report.SymbolRelatedToPreviousError (EventInfo);
3671 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3678 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3680 return DoResolve (ec);
3683 public override Expression DoResolve (EmitContext ec)
3685 bool must_do_cs1540_check;
3686 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3687 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3688 Report.SymbolRelatedToPreviousError (EventInfo);
3689 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3693 if (!InstanceResolve (ec, must_do_cs1540_check))
3699 public override void Emit (EmitContext ec)
3701 if (InstanceExpression is This)
3702 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3704 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3705 "(except on the defining type)", Name);
3708 public override string GetSignatureForError ()
3710 return TypeManager.CSharpSignature (EventInfo);
3713 public void EmitAddOrRemove (EmitContext ec, Expression source)
3715 BinaryDelegate source_del = (BinaryDelegate) source;
3716 Expression handler = source_del.Right;
3718 Argument arg = new Argument (handler, Argument.AType.Expression);
3719 ArrayList args = new ArrayList ();
3723 if (source_del.IsAddition)
3724 Invocation.EmitCall (
3725 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3727 Invocation.EmitCall (
3728 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3733 public class TemporaryVariable : Expression, IMemoryLocation
3737 public TemporaryVariable (Type type, Location loc)
3741 eclass = ExprClass.Value;
3744 public override Expression DoResolve (EmitContext ec)
3749 TypeExpr te = new TypeExpression (type, loc);
3750 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
3751 if (!li.Resolve (ec))
3754 AnonymousContainer am = ec.CurrentAnonymousMethod;
3755 if ((am != null) && am.IsIterator)
3756 ec.CaptureVariable (li);
3761 public override void Emit (EmitContext ec)
3763 ILGenerator ig = ec.ig;
3765 if (li.FieldBuilder != null) {
3766 ig.Emit (OpCodes.Ldarg_0);
3767 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
3769 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
3773 public void EmitLoadAddress (EmitContext ec)
3775 ILGenerator ig = ec.ig;
3777 if (li.FieldBuilder != null) {
3778 ig.Emit (OpCodes.Ldarg_0);
3779 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
3781 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
3785 public void Store (EmitContext ec, Expression right_side)
3787 if (li.FieldBuilder != null)
3788 ec.ig.Emit (OpCodes.Ldarg_0);
3790 right_side.Emit (ec);
3791 if (li.FieldBuilder != null) {
3792 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
3794 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
3798 public void EmitThis (EmitContext ec)
3800 if (li.FieldBuilder != null) {
3801 ec.ig.Emit (OpCodes.Ldarg_0);
3805 public void EmitStore (ILGenerator ig)
3807 if (li.FieldBuilder != null)
3808 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
3810 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
3813 public void AddressOf (EmitContext ec, AddressOp mode)
3815 EmitLoadAddress (ec);