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 virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
298 if (Type.Name == target.Name){
299 Report.ExtraInformation (loc,
301 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
302 Type.Name, Type.Assembly.FullName, target.Assembly.FullName));
307 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
308 GetSignatureForError (), TypeManager.CSharpName (target));
312 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
313 bool b = Convert.ExplicitNumericConversion (e, target) != null;
315 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
316 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
317 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
321 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
322 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
323 GetSignatureForError (), TypeManager.CSharpName (target));
327 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
328 Type == TypeManager.anonymous_method_type ?
329 "anonymous method" : "`" + GetSignatureForError () + "'",
330 TypeManager.CSharpName (target));
333 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
335 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
336 TypeManager.CSharpName (type), name);
339 ResolveFlags ExprClassToResolveFlags
344 case ExprClass.Namespace:
345 return ResolveFlags.Type;
347 case ExprClass.MethodGroup:
348 return ResolveFlags.MethodGroup;
350 case ExprClass.Value:
351 case ExprClass.Variable:
352 case ExprClass.PropertyAccess:
353 case ExprClass.EventAccess:
354 case ExprClass.IndexerAccess:
355 return ResolveFlags.VariableOrValue;
358 throw new Exception ("Expression " + GetType () +
359 " ExprClass is Invalid after resolve");
365 /// Resolves an expression and performs semantic analysis on it.
369 /// Currently Resolve wraps DoResolve to perform sanity
370 /// checking and assertion checking on what we expect from Resolve.
372 public Expression Resolve (EmitContext ec, ResolveFlags flags)
374 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
375 return ResolveAsTypeStep (ec, false);
377 bool old_do_flow_analysis = ec.DoFlowAnalysis;
378 bool old_omit_struct_analysis = ec.OmitStructFlowAnalysis;
379 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
380 ec.DoFlowAnalysis = false;
381 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
382 ec.OmitStructFlowAnalysis = true;
385 if (this is SimpleName) {
386 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
387 e = ((SimpleName) this).DoResolve (ec, intermediate);
392 ec.DoFlowAnalysis = old_do_flow_analysis;
393 ec.OmitStructFlowAnalysis = old_omit_struct_analysis;
398 if ((flags & e.ExprClassToResolveFlags) == 0) {
399 e.Error_UnexpectedKind (flags, loc);
403 if (e.type == null && !(e is Namespace)) {
404 throw new Exception (
405 "Expression " + e.GetType () +
406 " did not set its type after Resolve\n" +
407 "called from: " + this.GetType ());
414 /// Resolves an expression and performs semantic analysis on it.
416 public Expression Resolve (EmitContext ec)
418 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
420 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
421 ((MethodGroupExpr) e).ReportUsageError ();
427 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
429 Expression e = Resolve (ec);
433 Constant c = e as Constant;
437 Type constant_type = null;
438 if (mc is MemberBase) {
439 constant_type = ((MemberBase)mc).MemberType;
442 Const.Error_ExpressionMustBeConstant (constant_type, loc, mc.GetSignatureForError ());
447 /// Resolves an expression for LValue assignment
451 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
452 /// checking and assertion checking on what we expect from Resolve
454 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
456 int errors = Report.Errors;
457 bool out_access = right_side == EmptyExpression.OutAccess;
459 Expression e = DoResolveLValue (ec, right_side);
461 if (e != null && out_access && !(e is IMemoryLocation)) {
462 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
463 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
465 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
466 // e.GetType () + " " + e.GetSignatureForError ());
471 if (errors == Report.Errors) {
473 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
475 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
480 if (e.eclass == ExprClass.Invalid)
481 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
483 if (e.eclass == ExprClass.MethodGroup) {
484 ((MethodGroupExpr) e).ReportUsageError ();
489 throw new Exception ("Expression " + e + " did not set its type after Resolve");
495 /// Emits the code for the expression
499 /// The Emit method is invoked to generate the code
500 /// for the expression.
502 public abstract void Emit (EmitContext ec);
504 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
507 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
511 /// Protected constructor. Only derivate types should
512 /// be able to be created
515 protected Expression ()
517 eclass = ExprClass.Invalid;
522 /// Returns a literalized version of a literal FieldInfo
526 /// The possible return values are:
527 /// IntConstant, UIntConstant
528 /// LongLiteral, ULongConstant
529 /// FloatConstant, DoubleConstant
532 /// The value returned is already resolved.
534 public static Constant Constantify (object v, Type t)
536 if (t == TypeManager.int32_type)
537 return new IntConstant ((int) v, Location.Null);
538 else if (t == TypeManager.uint32_type)
539 return new UIntConstant ((uint) v, Location.Null);
540 else if (t == TypeManager.int64_type)
541 return new LongConstant ((long) v, Location.Null);
542 else if (t == TypeManager.uint64_type)
543 return new ULongConstant ((ulong) v, Location.Null);
544 else if (t == TypeManager.float_type)
545 return new FloatConstant ((float) v, Location.Null);
546 else if (t == TypeManager.double_type)
547 return new DoubleConstant ((double) v, Location.Null);
548 else if (t == TypeManager.string_type)
549 return new StringConstant ((string) v, Location.Null);
550 else if (t == TypeManager.short_type)
551 return new ShortConstant ((short)v, Location.Null);
552 else if (t == TypeManager.ushort_type)
553 return new UShortConstant ((ushort)v, Location.Null);
554 else if (t == TypeManager.sbyte_type)
555 return new SByteConstant ((sbyte)v, Location.Null);
556 else if (t == TypeManager.byte_type)
557 return new ByteConstant ((byte)v, Location.Null);
558 else if (t == TypeManager.char_type)
559 return new CharConstant ((char)v, Location.Null);
560 else if (t == TypeManager.bool_type)
561 return new BoolConstant ((bool) v, Location.Null);
562 else if (t == TypeManager.decimal_type)
563 return new DecimalConstant ((decimal) v, Location.Null);
564 else if (TypeManager.IsEnumType (t)){
565 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
567 real_type = System.Enum.GetUnderlyingType (real_type);
569 Constant e = Constantify (v, real_type);
571 return new EnumConstant (e, t);
572 } else if (v == null && !TypeManager.IsValueType (t))
573 return new NullLiteral (Location.Null);
575 throw new Exception ("Unknown type for constant (" + t +
580 /// Returns a fully formed expression after a MemberLookup
583 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
586 return new EventExpr ((EventInfo) mi, loc);
587 else if (mi is FieldInfo)
588 return new FieldExpr ((FieldInfo) mi, loc);
589 else if (mi is PropertyInfo)
590 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
591 else if (mi is Type){
592 return new TypeExpression ((System.Type) mi, loc);
598 protected static ArrayList almostMatchedMembers = new ArrayList (4);
601 // FIXME: Probably implement a cache for (t,name,current_access_set)?
603 // This code could use some optimizations, but we need to do some
604 // measurements. For example, we could use a delegate to `flag' when
605 // something can not any longer be a method-group (because it is something
609 // If the return value is an Array, then it is an array of
612 // If the return value is an MemberInfo, it is anything, but a Method
616 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
617 // the arguments here and have MemberLookup return only the methods that
618 // match the argument count/type, unlike we are doing now (we delay this
621 // This is so we can catch correctly attempts to invoke instance methods
622 // from a static body (scan for error 120 in ResolveSimpleName).
625 // FIXME: Potential optimization, have a static ArrayList
628 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
629 MemberTypes mt, BindingFlags bf, Location loc)
631 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
635 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
636 // `qualifier_type' or null to lookup members in the current class.
639 public static Expression MemberLookup (Type container_type,
640 Type qualifier_type, Type queried_type,
641 string name, MemberTypes mt,
642 BindingFlags bf, Location loc)
644 almostMatchedMembers.Clear ();
646 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
647 queried_type, mt, bf, name, almostMatchedMembers);
652 int count = mi.Length;
654 if (mi [0] is MethodBase)
655 return new MethodGroupExpr (mi, loc);
660 return ExprClassFromMemberInfo (container_type, mi [0], loc);
663 public const MemberTypes AllMemberTypes =
664 MemberTypes.Constructor |
668 MemberTypes.NestedType |
669 MemberTypes.Property;
671 public const BindingFlags AllBindingFlags =
672 BindingFlags.Public |
673 BindingFlags.Static |
674 BindingFlags.Instance;
676 public static Expression MemberLookup (Type container_type, Type queried_type,
677 string name, Location loc)
679 return MemberLookup (container_type, null, queried_type, name,
680 AllMemberTypes, AllBindingFlags, loc);
683 public static Expression MemberLookup (Type container_type, Type qualifier_type,
684 Type queried_type, string name, Location loc)
686 return MemberLookup (container_type, qualifier_type, queried_type,
687 name, AllMemberTypes, AllBindingFlags, loc);
690 public static Expression MethodLookup (EmitContext ec, Type queried_type,
691 string name, Location loc)
693 return MemberLookup (ec.ContainerType, null, queried_type, name,
694 MemberTypes.Method, AllBindingFlags, loc);
698 /// This is a wrapper for MemberLookup that is not used to "probe", but
699 /// to find a final definition. If the final definition is not found, we
700 /// look for private members and display a useful debugging message if we
703 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
704 Type queried_type, string name, Location loc)
706 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
707 AllMemberTypes, AllBindingFlags, loc);
710 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
711 Type queried_type, string name,
712 MemberTypes mt, BindingFlags bf,
717 int errors = Report.Errors;
719 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
721 if (e == null && errors == Report.Errors)
722 // No errors were reported by MemberLookup, but there was an error.
723 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
728 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
729 Type queried_type, string name,
730 string class_name, bool complain_if_none_found,
733 if (almostMatchedMembers.Count != 0) {
734 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
735 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
736 for (int j = 0; j < i; ++j) {
737 if (m == almostMatchedMembers [j]) {
745 Type declaring_type = m.DeclaringType;
747 Report.SymbolRelatedToPreviousError (m);
748 if (qualifier_type == null) {
749 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
750 TypeManager.CSharpName (m.DeclaringType),
751 TypeManager.CSharpName (container_type));
753 } else if (qualifier_type != container_type &&
754 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
755 // Although a derived class can access protected members of
756 // its base class it cannot do so through an instance of the
757 // base class (CS1540). If the qualifier_type is a base of the
758 // ec.ContainerType and the lookup succeeds with the latter one,
759 // then we are in this situation.
760 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
762 Report.SymbolRelatedToPreviousError (m);
763 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
766 almostMatchedMembers.Clear ();
770 MemberInfo[] lookup = null;
771 if (queried_type == null) {
772 class_name = "global::";
774 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
775 AllMemberTypes, AllBindingFlags |
776 BindingFlags.NonPublic, name, null);
779 if (lookup == null) {
780 if (!complain_if_none_found)
783 if (class_name != null)
784 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
787 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
791 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
792 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
793 if (name == ".ctor" && ml.Count == 0)
795 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
799 Report.SymbolRelatedToPreviousError (lookup [0]);
800 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
804 /// Returns an expression that can be used to invoke operator true
805 /// on the expression if it exists.
807 static public StaticCallExpr GetOperatorTrue (EmitContext ec, Expression e, Location loc)
809 return GetOperatorTrueOrFalse (ec, e, true, loc);
813 /// Returns an expression that can be used to invoke operator false
814 /// on the expression if it exists.
816 static public StaticCallExpr GetOperatorFalse (EmitContext ec, Expression e, Location loc)
818 return GetOperatorTrueOrFalse (ec, e, false, loc);
821 static StaticCallExpr GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
824 Expression operator_group;
826 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
827 if (operator_group == null)
830 ArrayList arguments = new ArrayList ();
831 arguments.Add (new Argument (e, Argument.AType.Expression));
832 method = Invocation.OverloadResolve (
833 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
838 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
842 /// Resolves the expression `e' into a boolean expression: either through
843 /// an implicit conversion, or through an `operator true' invocation
845 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
851 if (e.Type == TypeManager.bool_type)
854 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
856 if (converted != null)
860 // If no implicit conversion to bool exists, try using `operator true'
862 converted = Expression.GetOperatorTrue (ec, e, loc);
863 if (converted == null){
864 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
870 public virtual string ExprClassName
874 case ExprClass.Invalid:
876 case ExprClass.Value:
878 case ExprClass.Variable:
880 case ExprClass.Namespace:
884 case ExprClass.MethodGroup:
885 return "method group";
886 case ExprClass.PropertyAccess:
887 return "property access";
888 case ExprClass.EventAccess:
889 return "event access";
890 case ExprClass.IndexerAccess:
891 return "indexer access";
892 case ExprClass.Nothing:
895 throw new Exception ("Should not happen");
900 /// Reports that we were expecting `expr' to be of class `expected'
902 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
904 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
907 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
909 string name = GetSignatureForError ();
911 name = ds.GetSignatureForError () + '.' + name;
913 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
914 name, was, expected);
917 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
919 string [] valid = new string [4];
922 if ((flags & ResolveFlags.VariableOrValue) != 0) {
923 valid [count++] = "variable";
924 valid [count++] = "value";
927 if ((flags & ResolveFlags.Type) != 0)
928 valid [count++] = "type";
930 if ((flags & ResolveFlags.MethodGroup) != 0)
931 valid [count++] = "method group";
934 valid [count++] = "unknown";
936 StringBuilder sb = new StringBuilder (valid [0]);
937 for (int i = 1; i < count - 1; i++) {
939 sb.Append (valid [i]);
942 sb.Append ("' or `");
943 sb.Append (valid [count - 1]);
946 Report.Error (119, loc,
947 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
950 public static void UnsafeError (Location loc)
952 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
956 // Load the object from the pointer.
958 public static void LoadFromPtr (ILGenerator ig, Type t)
960 if (t == TypeManager.int32_type)
961 ig.Emit (OpCodes.Ldind_I4);
962 else if (t == TypeManager.uint32_type)
963 ig.Emit (OpCodes.Ldind_U4);
964 else if (t == TypeManager.short_type)
965 ig.Emit (OpCodes.Ldind_I2);
966 else if (t == TypeManager.ushort_type)
967 ig.Emit (OpCodes.Ldind_U2);
968 else if (t == TypeManager.char_type)
969 ig.Emit (OpCodes.Ldind_U2);
970 else if (t == TypeManager.byte_type)
971 ig.Emit (OpCodes.Ldind_U1);
972 else if (t == TypeManager.sbyte_type)
973 ig.Emit (OpCodes.Ldind_I1);
974 else if (t == TypeManager.uint64_type)
975 ig.Emit (OpCodes.Ldind_I8);
976 else if (t == TypeManager.int64_type)
977 ig.Emit (OpCodes.Ldind_I8);
978 else if (t == TypeManager.float_type)
979 ig.Emit (OpCodes.Ldind_R4);
980 else if (t == TypeManager.double_type)
981 ig.Emit (OpCodes.Ldind_R8);
982 else if (t == TypeManager.bool_type)
983 ig.Emit (OpCodes.Ldind_I1);
984 else if (t == TypeManager.intptr_type)
985 ig.Emit (OpCodes.Ldind_I);
986 else if (TypeManager.IsEnumType (t)) {
987 if (t == TypeManager.enum_type)
988 ig.Emit (OpCodes.Ldind_Ref);
990 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
991 } else if (t.IsValueType)
992 ig.Emit (OpCodes.Ldobj, t);
993 else if (t.IsPointer)
994 ig.Emit (OpCodes.Ldind_I);
996 ig.Emit (OpCodes.Ldind_Ref);
1000 // The stack contains the pointer and the value of type `type'
1002 public static void StoreFromPtr (ILGenerator ig, Type type)
1004 if (TypeManager.IsEnumType (type))
1005 type = TypeManager.EnumToUnderlying (type);
1006 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1007 ig.Emit (OpCodes.Stind_I4);
1008 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1009 ig.Emit (OpCodes.Stind_I8);
1010 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1011 type == TypeManager.ushort_type)
1012 ig.Emit (OpCodes.Stind_I2);
1013 else if (type == TypeManager.float_type)
1014 ig.Emit (OpCodes.Stind_R4);
1015 else if (type == TypeManager.double_type)
1016 ig.Emit (OpCodes.Stind_R8);
1017 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1018 type == TypeManager.bool_type)
1019 ig.Emit (OpCodes.Stind_I1);
1020 else if (type == TypeManager.intptr_type)
1021 ig.Emit (OpCodes.Stind_I);
1022 else if (type.IsValueType)
1023 ig.Emit (OpCodes.Stobj, type);
1025 ig.Emit (OpCodes.Stind_Ref);
1029 // Returns the size of type `t' if known, otherwise, 0
1031 public static int GetTypeSize (Type t)
1033 t = TypeManager.TypeToCoreType (t);
1034 if (t == TypeManager.int32_type ||
1035 t == TypeManager.uint32_type ||
1036 t == TypeManager.float_type)
1038 else if (t == TypeManager.int64_type ||
1039 t == TypeManager.uint64_type ||
1040 t == TypeManager.double_type)
1042 else if (t == TypeManager.byte_type ||
1043 t == TypeManager.sbyte_type ||
1044 t == TypeManager.bool_type)
1046 else if (t == TypeManager.short_type ||
1047 t == TypeManager.char_type ||
1048 t == TypeManager.ushort_type)
1050 else if (t == TypeManager.decimal_type)
1056 public static void Error_NegativeArrayIndex (Location loc)
1058 Report.Error (248, loc, "Cannot create an array with a negative size");
1061 protected void Error_CannotCallAbstractBase (string name)
1063 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1067 // Converts `source' to an int, uint, long or ulong.
1069 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1073 bool old_checked = ec.CheckState;
1074 ec.CheckState = true;
1076 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1077 if (target == null){
1078 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1079 if (target == null){
1080 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1081 if (target == null){
1082 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1084 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1088 ec.CheckState = old_checked;
1091 // Only positive constants are allowed at compile time
1093 if (target is Constant){
1094 if (target is IntConstant){
1095 if (((IntConstant) target).Value < 0){
1096 Error_NegativeArrayIndex (loc);
1101 if (target is LongConstant){
1102 if (((LongConstant) target).Value < 0){
1103 Error_NegativeArrayIndex (loc);
1116 /// This is just a base class for expressions that can
1117 /// appear on statements (invocations, object creation,
1118 /// assignments, post/pre increment and decrement). The idea
1119 /// being that they would support an extra Emition interface that
1120 /// does not leave a result on the stack.
1122 public abstract class ExpressionStatement : Expression {
1124 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1126 Expression e = Resolve (ec);
1130 ExpressionStatement es = e as ExpressionStatement;
1132 Error (201, "Only assignment, call, increment, decrement and new object " +
1133 "expressions can be used as a statement");
1139 /// Requests the expression to be emitted in a `statement'
1140 /// context. This means that no new value is left on the
1141 /// stack after invoking this method (constrasted with
1142 /// Emit that will always leave a value on the stack).
1144 public abstract void EmitStatement (EmitContext ec);
1148 /// This kind of cast is used to encapsulate the child
1149 /// whose type is child.Type into an expression that is
1150 /// reported to return "return_type". This is used to encapsulate
1151 /// expressions which have compatible types, but need to be dealt
1152 /// at higher levels with.
1154 /// For example, a "byte" expression could be encapsulated in one
1155 /// of these as an "unsigned int". The type for the expression
1156 /// would be "unsigned int".
1159 public class EmptyCast : Expression {
1160 protected readonly Expression child;
1162 public EmptyCast (Expression child, Type return_type)
1164 eclass = child.eclass;
1165 loc = child.Location;
1170 public override Expression DoResolve (EmitContext ec)
1172 // This should never be invoked, we are born in fully
1173 // initialized state.
1178 public override void Emit (EmitContext ec)
1183 public override bool GetAttributableValue (Type valueType, out object value)
1185 return child.GetAttributableValue (valueType, out value);
1190 /// This is a numeric cast to a Decimal
1192 public class CastToDecimal : EmptyCast {
1194 MethodInfo conversion_operator;
1196 public CastToDecimal (Expression child)
1197 : this (child, false)
1201 public CastToDecimal (Expression child, bool find_explicit)
1202 : base (child, TypeManager.decimal_type)
1204 conversion_operator = GetConversionOperator (find_explicit);
1206 if (conversion_operator == null)
1207 throw new InternalErrorException ("Outer conversion routine is out of sync");
1210 // Returns the implicit operator that converts from
1211 // 'child.Type' to System.Decimal.
1212 MethodInfo GetConversionOperator (bool find_explicit)
1214 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1216 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1217 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1219 foreach (MethodInfo oper in mi) {
1220 ParameterData pd = TypeManager.GetParameterData (oper);
1222 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1228 public override void Emit (EmitContext ec)
1230 ILGenerator ig = ec.ig;
1233 ig.Emit (OpCodes.Call, conversion_operator);
1238 /// This is an explicit numeric cast from a Decimal
1240 public class CastFromDecimal : EmptyCast
1242 static IDictionary operators;
1244 public CastFromDecimal (Expression child, Type return_type)
1245 : base (child, return_type)
1247 if (child.Type != TypeManager.decimal_type)
1248 throw new InternalErrorException (
1249 "The expected type is Decimal, instead it is " + child.Type.FullName);
1252 // Returns the explicit operator that converts from an
1253 // express of type System.Decimal to 'type'.
1254 public Expression Resolve ()
1256 if (operators == null) {
1257 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1258 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1259 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1261 operators = new System.Collections.Specialized.HybridDictionary ();
1262 foreach (MethodInfo oper in all_oper) {
1263 ParameterData pd = TypeManager.GetParameterData (oper);
1264 if (pd.ParameterType (0) == TypeManager.decimal_type)
1265 operators.Add (oper.ReturnType, oper);
1269 return operators.Contains (type) ? this : null;
1272 public override void Emit (EmitContext ec)
1274 ILGenerator ig = ec.ig;
1277 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1282 // We need to special case this since an empty cast of
1283 // a NullLiteral is still a Constant
1285 public class NullCast : Constant {
1286 public Constant child;
1288 public NullCast (Constant child, Type return_type):
1289 base (Location.Null)
1291 eclass = child.eclass;
1296 override public string AsString ()
1301 public override object GetValue ()
1306 public override Expression DoResolve (EmitContext ec)
1308 // This should never be invoked, we are born in fully
1309 // initialized state.
1314 public override void Emit (EmitContext ec)
1319 public override Constant Increment ()
1321 throw new NotSupportedException ();
1324 public override bool IsDefaultValue {
1330 public override bool IsNegative {
1336 public override Constant Reduce (bool inCheckedContext, Type target_type)
1338 if (type == target_type)
1339 return child.Reduce (inCheckedContext, target_type);
1348 /// This class is used to wrap literals which belong inside Enums
1350 public class EnumConstant : Constant {
1351 public Constant Child;
1353 public EnumConstant (Constant child, Type enum_type):
1354 base (child.Location)
1356 eclass = child.eclass;
1361 public override Expression DoResolve (EmitContext ec)
1363 // This should never be invoked, we are born in fully
1364 // initialized state.
1369 public override void Emit (EmitContext ec)
1374 public override bool GetAttributableValue (Type valueType, out object value)
1376 value = GetTypedValue ();
1380 public override string GetSignatureForError()
1382 return TypeManager.CSharpName (Type);
1385 public override object GetValue ()
1387 return Child.GetValue ();
1390 public override object GetTypedValue ()
1392 // FIXME: runtime is not ready to work with just emited enums
1393 if (!RootContext.StdLib) {
1394 return Child.GetValue ();
1397 return System.Enum.ToObject (type, Child.GetValue ());
1400 public override string AsString ()
1402 return Child.AsString ();
1405 public override DoubleConstant ConvertToDouble ()
1407 return Child.ConvertToDouble ();
1410 public override FloatConstant ConvertToFloat ()
1412 return Child.ConvertToFloat ();
1415 public override ULongConstant ConvertToULong ()
1417 return Child.ConvertToULong ();
1420 public override LongConstant ConvertToLong ()
1422 return Child.ConvertToLong ();
1425 public override UIntConstant ConvertToUInt ()
1427 return Child.ConvertToUInt ();
1430 public override IntConstant ConvertToInt ()
1432 return Child.ConvertToInt ();
1435 public override Constant Increment()
1437 return new EnumConstant (Child.Increment (), type);
1440 public override bool IsDefaultValue {
1442 return Child.IsDefaultValue;
1446 public override bool IsZeroInteger {
1447 get { return Child.IsZeroInteger; }
1450 public override bool IsNegative {
1452 return Child.IsNegative;
1456 public override Constant Reduce(bool inCheckedContext, Type target_type)
1458 if (Child.Type == target_type)
1461 return Child.Reduce (inCheckedContext, target_type);
1464 public override Constant ToType (Type type, Location loc)
1467 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1468 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1471 if (type.UnderlyingSystemType != Child.Type)
1472 Child = Child.ToType (type.UnderlyingSystemType, loc);
1476 if (!Convert.ImplicitStandardConversionExists (this, type)){
1477 Error_ValueCannotBeConverted (loc, type, false);
1481 return Child.ToType (type, loc);
1487 /// This kind of cast is used to encapsulate Value Types in objects.
1489 /// The effect of it is to box the value type emitted by the previous
1492 public class BoxedCast : EmptyCast {
1494 public BoxedCast (Expression expr, Type target_type)
1495 : base (expr, target_type)
1497 eclass = ExprClass.Value;
1500 public override Expression DoResolve (EmitContext ec)
1502 // This should never be invoked, we are born in fully
1503 // initialized state.
1508 public override void Emit (EmitContext ec)
1512 ec.ig.Emit (OpCodes.Box, child.Type);
1516 public class UnboxCast : EmptyCast {
1517 public UnboxCast (Expression expr, Type return_type)
1518 : base (expr, return_type)
1522 public override Expression DoResolve (EmitContext ec)
1524 // This should never be invoked, we are born in fully
1525 // initialized state.
1530 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1532 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1533 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1534 return base.DoResolveLValue (ec, right_side);
1537 public override void Emit (EmitContext ec)
1540 ILGenerator ig = ec.ig;
1543 ig.Emit (OpCodes.Unbox, t);
1545 LoadFromPtr (ig, t);
1550 /// This is used to perform explicit numeric conversions.
1552 /// Explicit numeric conversions might trigger exceptions in a checked
1553 /// context, so they should generate the conv.ovf opcodes instead of
1556 public class ConvCast : EmptyCast {
1557 public enum Mode : byte {
1558 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1560 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1561 U2_I1, U2_U1, U2_I2, U2_CH,
1562 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1563 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1564 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1565 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1566 CH_I1, CH_U1, CH_I2,
1567 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1568 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1573 public ConvCast (Expression child, Type return_type, Mode m)
1574 : base (child, return_type)
1579 public override Expression DoResolve (EmitContext ec)
1581 // This should never be invoked, we are born in fully
1582 // initialized state.
1587 public override string ToString ()
1589 return String.Format ("ConvCast ({0}, {1})", mode, child);
1592 public override void Emit (EmitContext ec)
1594 ILGenerator ig = ec.ig;
1600 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1601 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1602 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1603 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1604 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1606 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1607 case Mode.U1_CH: /* nothing */ break;
1609 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1610 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1611 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1612 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1613 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1614 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1616 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1617 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1618 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1619 case Mode.U2_CH: /* nothing */ break;
1621 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1622 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1623 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1624 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1625 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1626 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1627 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1629 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1630 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1631 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1632 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1633 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1634 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1636 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1637 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1638 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1639 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1640 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1641 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1642 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1643 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1645 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1646 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1647 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1648 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1649 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1650 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1651 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1652 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1654 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1655 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1656 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1658 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1659 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1660 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1661 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1662 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1663 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1664 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1665 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1666 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1668 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1669 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1670 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1671 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1672 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1673 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1674 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1675 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1676 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1677 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1681 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1682 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1683 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1684 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1685 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1687 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1688 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1690 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1691 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1692 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1693 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1694 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1695 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1697 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1698 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1699 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1700 case Mode.U2_CH: /* nothing */ break;
1702 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1703 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1704 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1705 case Mode.I4_U4: /* nothing */ break;
1706 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1707 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1708 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1710 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1711 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1712 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1713 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1714 case Mode.U4_I4: /* nothing */ break;
1715 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1717 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1718 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1719 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1720 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1721 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1722 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1723 case Mode.I8_U8: /* nothing */ break;
1724 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1726 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1727 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1728 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1729 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1730 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1731 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1732 case Mode.U8_I8: /* nothing */ break;
1733 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1735 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1736 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1737 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1739 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1740 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1741 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1742 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1743 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1744 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1745 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1746 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1747 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1749 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1750 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1751 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1752 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1753 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1754 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1755 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1756 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1757 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1758 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1764 public class OpcodeCast : EmptyCast {
1768 public OpcodeCast (Expression child, Type return_type, OpCode op)
1769 : base (child, return_type)
1773 second_valid = false;
1776 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1777 : base (child, return_type)
1782 second_valid = true;
1785 public override Expression DoResolve (EmitContext ec)
1787 // This should never be invoked, we are born in fully
1788 // initialized state.
1793 public override void Emit (EmitContext ec)
1804 /// This kind of cast is used to encapsulate a child and cast it
1805 /// to the class requested
1807 public class ClassCast : EmptyCast {
1808 public ClassCast (Expression child, Type return_type)
1809 : base (child, return_type)
1814 public override Expression DoResolve (EmitContext ec)
1816 // This should never be invoked, we are born in fully
1817 // initialized state.
1822 public override void Emit (EmitContext ec)
1826 ec.ig.Emit (OpCodes.Castclass, type);
1832 /// SimpleName expressions are formed of a single word and only happen at the beginning
1833 /// of a dotted-name.
1835 public class SimpleName : Expression {
1839 public SimpleName (string name, Location l)
1845 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1847 if (ec.IsFieldInitializer)
1848 Report.Error (236, l,
1849 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1853 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1857 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1859 return resolved_to != null && resolved_to.Type != null &&
1860 resolved_to.Type.Name == Name &&
1861 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1864 public override Expression DoResolve (EmitContext ec)
1866 return SimpleNameResolve (ec, null, false);
1869 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1871 return SimpleNameResolve (ec, right_side, false);
1875 public Expression DoResolve (EmitContext ec, bool intermediate)
1877 return SimpleNameResolve (ec, null, intermediate);
1880 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
1882 int errors = Report.Errors;
1883 FullNamedExpression fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
1887 if (silent || errors != Report.Errors)
1890 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
1892 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
1896 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
1897 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
1898 foreach (Assembly a in RootNamespace.Global.Assemblies) {
1899 Type type = a.GetType (fullname);
1901 Report.SymbolRelatedToPreviousError (type);
1902 Expression.ErrorIsInaccesible (loc, fullname);
1907 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
1911 // TODO: I am still not convinced about this. If someone else will need it
1912 // implement this as virtual property in MemberCore hierarchy
1913 string GetMemberType (MemberCore mc)
1915 if (mc is PropertyBase)
1919 if (mc is FieldBase)
1921 if (mc is MethodCore)
1923 if (mc is EnumMember)
1929 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
1935 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
1939 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
1946 /// 7.5.2: Simple Names.
1948 /// Local Variables and Parameters are handled at
1949 /// parse time, so they never occur as SimpleNames.
1951 /// The `intermediate' flag is used by MemberAccess only
1952 /// and it is used to inform us that it is ok for us to
1953 /// avoid the static check, because MemberAccess might end
1954 /// up resolving the Name as a Type name and the access as
1955 /// a static type access.
1957 /// ie: Type Type; .... { Type.GetType (""); }
1959 /// Type is both an instance variable and a Type; Type.GetType
1960 /// is the static method not an instance method of type.
1962 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
1964 Expression e = null;
1967 // Stage 1: Performed by the parser (binding to locals or parameters).
1969 Block current_block = ec.CurrentBlock;
1970 if (current_block != null){
1971 LocalInfo vi = current_block.GetLocalInfo (Name);
1973 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
1974 if (right_side != null) {
1975 return var.ResolveLValue (ec, right_side, loc);
1977 ResolveFlags rf = ResolveFlags.VariableOrValue;
1979 rf |= ResolveFlags.DisableFlowAnalysis;
1980 return var.Resolve (ec, rf);
1984 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
1986 if (right_side != null)
1987 return pref.ResolveLValue (ec, right_side, loc);
1989 return pref.Resolve (ec);
1994 // Stage 2: Lookup members
1997 DeclSpace lookup_ds = ec.DeclContainer;
1998 Type almost_matched_type = null;
1999 ArrayList almost_matched = null;
2001 if (lookup_ds.TypeBuilder == null)
2004 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2008 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2009 almost_matched_type = lookup_ds.TypeBuilder;
2010 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2013 lookup_ds =lookup_ds.Parent;
2014 } while (lookup_ds != null);
2016 if (e == null && ec.ContainerType != null)
2017 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2020 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2021 almost_matched_type = ec.ContainerType;
2022 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2024 e = ResolveAsTypeStep (ec, true);
2028 if (almost_matched != null)
2029 almostMatchedMembers = almost_matched;
2030 if (almost_matched_type == null)
2031 almost_matched_type = ec.ContainerType;
2032 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2039 if (e is MemberExpr) {
2040 MemberExpr me = (MemberExpr) e;
2043 if (me.IsInstance) {
2044 if (ec.IsStatic || ec.IsFieldInitializer) {
2046 // Note that an MemberExpr can be both IsInstance and IsStatic.
2047 // An unresolved MethodGroupExpr can contain both kinds of methods
2048 // and each predicate is true if the MethodGroupExpr contains
2049 // at least one of that kind of method.
2053 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2054 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2055 return EmptyExpression.Null;
2059 // Pass the buck to MemberAccess and Invocation.
2061 left = EmptyExpression.Null;
2063 left = ec.GetThis (loc);
2066 left = new TypeExpression (ec.ContainerType, loc);
2069 e = me.ResolveMemberAccess (ec, left, loc, null);
2073 me = e as MemberExpr;
2078 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2079 me.InstanceExpression.Type != me.DeclaringType &&
2080 !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType) &&
2081 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2082 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2083 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2087 return (right_side != null)
2088 ? me.DoResolveLValue (ec, right_side)
2089 : me.DoResolve (ec);
2095 public override void Emit (EmitContext ec)
2098 // If this is ever reached, then we failed to
2099 // find the name as a namespace
2102 Error (103, "The name `" + Name +
2103 "' does not exist in the class `" +
2104 ec.DeclContainer.Name + "'");
2107 public override string ToString ()
2112 public override string GetSignatureForError ()
2119 /// Represents a namespace or a type. The name of the class was inspired by
2120 /// section 10.8.1 (Fully Qualified Names).
2122 public abstract class FullNamedExpression : Expression {
2123 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2128 public abstract string FullName {
2134 /// Expression that evaluates to a type
2136 public abstract class TypeExpr : FullNamedExpression {
2137 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2139 TypeExpr t = DoResolveAsTypeStep (ec);
2143 eclass = ExprClass.Type;
2147 override public Expression DoResolve (EmitContext ec)
2149 return ResolveAsTypeTerminal (ec, false);
2152 override public void Emit (EmitContext ec)
2154 throw new Exception ("Should never be called");
2157 public virtual bool CheckAccessLevel (DeclSpace ds)
2159 return ds.CheckAccessLevel (Type);
2162 public virtual bool AsAccessible (DeclSpace ds, int flags)
2164 return ds.AsAccessible (Type, flags);
2167 public virtual bool IsClass {
2168 get { return Type.IsClass; }
2171 public virtual bool IsValueType {
2172 get { return Type.IsValueType; }
2175 public virtual bool IsInterface {
2176 get { return Type.IsInterface; }
2179 public virtual bool IsSealed {
2180 get { return Type.IsSealed; }
2183 public virtual bool CanInheritFrom ()
2185 if (Type == TypeManager.enum_type ||
2186 (Type == TypeManager.value_type && RootContext.StdLib) ||
2187 Type == TypeManager.multicast_delegate_type ||
2188 Type == TypeManager.delegate_type ||
2189 Type == TypeManager.array_type)
2195 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2197 public abstract string Name {
2201 public override bool Equals (object obj)
2203 TypeExpr tobj = obj as TypeExpr;
2207 return Type == tobj.Type;
2210 public override int GetHashCode ()
2212 return Type.GetHashCode ();
2215 public override string ToString ()
2222 /// Fully resolved Expression that already evaluated to a type
2224 public class TypeExpression : TypeExpr {
2225 public TypeExpression (Type t, Location l)
2228 eclass = ExprClass.Type;
2232 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2237 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2242 public override string Name {
2243 get { return Type.ToString (); }
2246 public override string FullName {
2247 get { return Type.FullName; }
2252 /// Used to create types from a fully qualified name. These are just used
2253 /// by the parser to setup the core types. A TypeLookupExpression is always
2254 /// classified as a type.
2256 public sealed class TypeLookupExpression : TypeExpr {
2257 readonly string name;
2259 public TypeLookupExpression (string name)
2262 eclass = ExprClass.Type;
2265 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2267 // It's null for corlib compilation only
2269 return DoResolveAsTypeStep (ec);
2274 static readonly char [] dot_array = { '.' };
2275 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2277 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2279 string lookup_name = name;
2280 int pos = name.IndexOf ('.');
2282 rest = name.Substring (pos + 1);
2283 lookup_name = name.Substring (0, pos);
2286 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2288 if (resolved != null && rest != null) {
2289 // Now handle the rest of the the name.
2290 string [] elements = rest.Split (dot_array);
2292 int count = elements.Length;
2294 while (i < count && resolved != null && resolved is Namespace) {
2295 Namespace ns = resolved as Namespace;
2296 element = elements [i++];
2297 lookup_name += "." + element;
2298 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2301 if (resolved != null && resolved is TypeExpr) {
2302 Type t = ((TypeExpr) resolved).Type;
2304 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2306 lookup_name = t.FullName;
2313 t = TypeManager.GetNestedType (t, elements [i++]);
2318 if (resolved == null) {
2319 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2323 if (!(resolved is TypeExpr)) {
2324 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2328 type = resolved.Type;
2332 public override string Name {
2333 get { return name; }
2336 public override string FullName {
2337 get { return name; }
2341 public class TypeAliasExpression : TypeExpr {
2344 public TypeAliasExpression (TypeExpr texpr, Location l)
2347 loc = texpr.Location;
2349 eclass = ExprClass.Type;
2352 public override string Name {
2353 get { return texpr.Name; }
2356 public override string FullName {
2357 get { return texpr.FullName; }
2360 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2365 public override bool CheckAccessLevel (DeclSpace ds)
2367 return texpr.CheckAccessLevel (ds);
2370 public override bool AsAccessible (DeclSpace ds, int flags)
2372 return texpr.AsAccessible (ds, flags);
2375 public override bool IsClass {
2376 get { return texpr.IsClass; }
2379 public override bool IsValueType {
2380 get { return texpr.IsValueType; }
2383 public override bool IsInterface {
2384 get { return texpr.IsInterface; }
2387 public override bool IsSealed {
2388 get { return texpr.IsSealed; }
2393 /// This class denotes an expression which evaluates to a member
2394 /// of a struct or a class.
2396 public abstract class MemberExpr : Expression
2399 /// The name of this member.
2401 public abstract string Name {
2406 /// Whether this is an instance member.
2408 public abstract bool IsInstance {
2413 /// Whether this is a static member.
2415 public abstract bool IsStatic {
2420 /// The type which declares this member.
2422 public abstract Type DeclaringType {
2427 /// The instance expression associated with this member, if it's a
2428 /// non-static member.
2430 public Expression InstanceExpression;
2432 public static void error176 (Location loc, string name)
2434 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2435 "with an instance reference, qualify it with a type name instead", name);
2438 // TODO: possible optimalization
2439 // Cache resolved constant result in FieldBuilder <-> expression map
2440 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2441 SimpleName original)
2445 // original == null || original.Resolve (...) ==> left
2448 if (left is TypeExpr) {
2450 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2458 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2461 error176 (loc, GetSignatureForError ());
2465 InstanceExpression = left;
2470 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2475 if (InstanceExpression == EmptyExpression.Null) {
2476 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2480 if (InstanceExpression.Type.IsValueType) {
2481 if (InstanceExpression is IMemoryLocation) {
2482 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2484 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2485 InstanceExpression.Emit (ec);
2487 t.AddressOf (ec, AddressOp.Store);
2490 InstanceExpression.Emit (ec);
2492 if (prepare_for_load)
2493 ec.ig.Emit (OpCodes.Dup);
2498 /// MethodGroup Expression.
2500 /// This is a fully resolved expression that evaluates to a type
2502 public class MethodGroupExpr : MemberExpr {
2503 public MethodBase [] Methods;
2504 bool identical_type_name = false;
2507 public MethodGroupExpr (MemberInfo [] mi, Location l)
2509 Methods = new MethodBase [mi.Length];
2510 mi.CopyTo (Methods, 0);
2511 eclass = ExprClass.MethodGroup;
2512 type = TypeManager.object_type;
2516 public MethodGroupExpr (ArrayList list, Location l)
2518 Methods = new MethodBase [list.Count];
2521 list.CopyTo (Methods, 0);
2523 foreach (MemberInfo m in list){
2524 if (!(m is MethodBase)){
2525 Console.WriteLine ("Name " + m.Name);
2526 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2533 eclass = ExprClass.MethodGroup;
2534 type = TypeManager.object_type;
2537 public override Type DeclaringType {
2540 // The methods are arranged in this order:
2541 // derived type -> base type
2543 return Methods [0].DeclaringType;
2547 public bool IdenticalTypeName {
2549 return identical_type_name;
2553 identical_type_name = value;
2557 public bool IsBase {
2566 public override string GetSignatureForError ()
2568 return TypeManager.CSharpSignature (Methods [0]);
2571 public override string Name {
2573 return Methods [0].Name;
2577 public override bool IsInstance {
2579 foreach (MethodBase mb in Methods)
2587 public override bool IsStatic {
2589 foreach (MethodBase mb in Methods)
2597 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2598 SimpleName original)
2600 if (!(left is TypeExpr) &&
2601 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2602 IdenticalTypeName = true;
2604 return base.ResolveMemberAccess (ec, left, loc, original);
2607 override public Expression DoResolve (EmitContext ec)
2610 InstanceExpression = null;
2612 if (InstanceExpression != null) {
2613 InstanceExpression = InstanceExpression.DoResolve (ec);
2614 if (InstanceExpression == null)
2621 public void ReportUsageError ()
2623 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2624 Name + "()' is referenced without parentheses");
2627 override public void Emit (EmitContext ec)
2629 ReportUsageError ();
2632 bool RemoveMethods (bool keep_static)
2634 ArrayList smethods = new ArrayList ();
2636 foreach (MethodBase mb in Methods){
2637 if (mb.IsStatic == keep_static)
2641 if (smethods.Count == 0)
2644 Methods = new MethodBase [smethods.Count];
2645 smethods.CopyTo (Methods, 0);
2651 /// Removes any instance methods from the MethodGroup, returns
2652 /// false if the resulting set is empty.
2654 public bool RemoveInstanceMethods ()
2656 return RemoveMethods (true);
2660 /// Removes any static methods from the MethodGroup, returns
2661 /// false if the resulting set is empty.
2663 public bool RemoveStaticMethods ()
2665 return RemoveMethods (false);
2670 /// Fully resolved expression that evaluates to a Field
2672 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2673 public readonly FieldInfo FieldInfo;
2674 VariableInfo variable_info;
2676 LocalTemporary temp;
2678 bool in_initializer;
2680 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2683 this.in_initializer = in_initializer;
2686 public FieldExpr (FieldInfo fi, Location l)
2689 eclass = ExprClass.Variable;
2690 type = fi.FieldType;
2694 public override string Name {
2696 return FieldInfo.Name;
2700 public override bool IsInstance {
2702 return !FieldInfo.IsStatic;
2706 public override bool IsStatic {
2708 return FieldInfo.IsStatic;
2712 public override Type DeclaringType {
2714 return FieldInfo.DeclaringType;
2718 public override string GetSignatureForError ()
2720 return TypeManager.GetFullNameSignature (FieldInfo);
2723 public VariableInfo VariableInfo {
2725 return variable_info;
2729 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2730 SimpleName original)
2732 Type t = FieldInfo.FieldType;
2734 if (FieldInfo.IsLiteral || (FieldInfo.IsInitOnly && t == TypeManager.decimal_type)) {
2735 IConstant ic = TypeManager.GetConstant (FieldInfo);
2737 if (FieldInfo.IsLiteral) {
2738 ic = new ExternalConstant (FieldInfo);
2740 ic = ExternalConstant.CreateDecimal (FieldInfo);
2742 return base.ResolveMemberAccess (ec, left, loc, original);
2745 TypeManager.RegisterConstant (FieldInfo, ic);
2748 bool left_is_type = left is TypeExpr;
2749 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
2750 Report.SymbolRelatedToPreviousError (FieldInfo);
2751 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
2755 if (ic.ResolveValue ()) {
2756 if (!ec.IsInObsoleteScope)
2757 ic.CheckObsoleteness (loc);
2763 if (t.IsPointer && !ec.InUnsafe) {
2768 return base.ResolveMemberAccess (ec, left, loc, original);
2771 override public Expression DoResolve (EmitContext ec)
2773 return DoResolve (ec, false, false);
2776 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
2778 if (!FieldInfo.IsStatic){
2779 if (InstanceExpression == null){
2781 // This can happen when referencing an instance field using
2782 // a fully qualified type expression: TypeName.InstanceField = xxx
2784 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2788 // Resolve the field's instance expression while flow analysis is turned
2789 // off: when accessing a field "a.b", we must check whether the field
2790 // "a.b" is initialized, not whether the whole struct "a" is initialized.
2792 if (lvalue_instance) {
2793 bool old_do_flow_analysis = ec.DoFlowAnalysis;
2794 ec.DoFlowAnalysis = false;
2795 Expression right_side =
2796 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
2797 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
2798 ec.DoFlowAnalysis = old_do_flow_analysis;
2800 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
2801 InstanceExpression = InstanceExpression.Resolve (ec, rf);
2804 if (InstanceExpression == null)
2807 InstanceExpression.CheckMarshalByRefAccess ();
2810 if (!in_initializer && !ec.IsFieldInitializer) {
2811 ObsoleteAttribute oa;
2812 FieldBase f = TypeManager.GetField (FieldInfo);
2814 if (!ec.IsInObsoleteScope)
2815 f.CheckObsoleteness (loc);
2817 // To be sure that type is external because we do not register generated fields
2818 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
2819 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
2821 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
2825 AnonymousContainer am = ec.CurrentAnonymousMethod;
2827 if (!FieldInfo.IsStatic){
2828 if (!am.IsIterator && (ec.TypeContainer is Struct)){
2829 Report.Error (1673, loc,
2830 "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",
2834 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
2835 ec.CaptureField (this);
2839 // If the instance expression is a local variable or parameter.
2840 IVariable var = InstanceExpression as IVariable;
2841 if ((var == null) || (var.VariableInfo == null))
2844 VariableInfo vi = var.VariableInfo;
2845 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
2848 variable_info = vi.GetSubStruct (FieldInfo.Name);
2852 static readonly int [] codes = {
2853 191, // instance, write access
2854 192, // instance, out access
2855 198, // static, write access
2856 199, // static, out access
2857 1648, // member of value instance, write access
2858 1649, // member of value instance, out access
2859 1650, // member of value static, write access
2860 1651 // member of value static, out access
2863 static readonly string [] msgs = {
2864 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
2865 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2866 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2867 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
2868 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
2869 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2870 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2871 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
2874 // The return value is always null. Returning a value simplifies calling code.
2875 Expression Report_AssignToReadonly (Expression right_side)
2878 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
2882 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
2884 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
2889 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
2891 IVariable var = InstanceExpression as IVariable;
2892 if ((var != null) && (var.VariableInfo != null))
2893 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
2895 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
2896 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
2898 Expression e = DoResolve (ec, lvalue_instance, out_access);
2903 FieldBase fb = TypeManager.GetField (FieldInfo);
2907 if (FieldInfo.IsInitOnly) {
2908 // InitOnly fields can only be assigned in constructors or initializers
2909 if (!ec.IsFieldInitializer && !ec.IsConstructor)
2910 return Report_AssignToReadonly (right_side);
2912 if (ec.IsConstructor) {
2913 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
2914 if (ec.ContainerType != FieldInfo.DeclaringType)
2915 return Report_AssignToReadonly (right_side);
2916 // static InitOnly fields cannot be assigned-to in an instance constructor
2917 if (IsStatic && !ec.IsStatic)
2918 return Report_AssignToReadonly (right_side);
2919 // instance constructors can't modify InitOnly fields of other instances of the same type
2920 if (!IsStatic && !(InstanceExpression is This))
2921 return Report_AssignToReadonly (right_side);
2925 if (right_side == EmptyExpression.OutAccess &&
2926 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
2927 Report.SymbolRelatedToPreviousError (DeclaringType);
2928 Report.Warning (197, 1, loc,
2929 "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",
2930 GetSignatureForError ());
2936 public override void CheckMarshalByRefAccess ()
2938 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
2939 Report.SymbolRelatedToPreviousError (DeclaringType);
2940 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",
2941 GetSignatureForError ());
2945 public bool VerifyFixed ()
2947 IVariable variable = InstanceExpression as IVariable;
2948 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
2949 // We defer the InstanceExpression check after the variable check to avoid a
2950 // separate null check on InstanceExpression.
2951 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
2954 public override int GetHashCode ()
2956 return FieldInfo.GetHashCode ();
2959 public override bool Equals (object obj)
2961 FieldExpr fe = obj as FieldExpr;
2965 if (FieldInfo != fe.FieldInfo)
2968 if (InstanceExpression == null || fe.InstanceExpression == null)
2971 return InstanceExpression.Equals (fe.InstanceExpression);
2974 public void Emit (EmitContext ec, bool leave_copy)
2976 ILGenerator ig = ec.ig;
2977 bool is_volatile = false;
2979 FieldBase f = TypeManager.GetField (FieldInfo);
2981 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
2984 f.SetMemberIsUsed ();
2987 if (FieldInfo.IsStatic){
2989 ig.Emit (OpCodes.Volatile);
2991 ig.Emit (OpCodes.Ldsfld, FieldInfo);
2994 EmitInstance (ec, false);
2997 ig.Emit (OpCodes.Volatile);
2999 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3002 ig.Emit (OpCodes.Ldflda, FieldInfo);
3003 ig.Emit (OpCodes.Ldflda, ff.Element);
3006 ig.Emit (OpCodes.Ldfld, FieldInfo);
3011 ec.ig.Emit (OpCodes.Dup);
3012 if (!FieldInfo.IsStatic) {
3013 temp = new LocalTemporary (this.Type);
3019 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3021 FieldAttributes fa = FieldInfo.Attributes;
3022 bool is_static = (fa & FieldAttributes.Static) != 0;
3023 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3024 ILGenerator ig = ec.ig;
3025 prepared = prepare_for_load;
3027 if (is_readonly && !ec.IsConstructor){
3028 Report_AssignToReadonly (source);
3032 EmitInstance (ec, prepare_for_load);
3036 ec.ig.Emit (OpCodes.Dup);
3037 if (!FieldInfo.IsStatic) {
3038 temp = new LocalTemporary (this.Type);
3043 if (FieldInfo is FieldBuilder){
3044 FieldBase f = TypeManager.GetField (FieldInfo);
3046 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3047 ig.Emit (OpCodes.Volatile);
3054 ig.Emit (OpCodes.Stsfld, FieldInfo);
3056 ig.Emit (OpCodes.Stfld, FieldInfo);
3062 public override void Emit (EmitContext ec)
3067 public void AddressOf (EmitContext ec, AddressOp mode)
3069 ILGenerator ig = ec.ig;
3071 if (FieldInfo is FieldBuilder){
3072 FieldBase f = TypeManager.GetField (FieldInfo);
3074 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3075 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3076 f.GetSignatureForError ());
3080 if ((mode & AddressOp.Store) != 0)
3082 if ((mode & AddressOp.Load) != 0)
3083 f.SetMemberIsUsed ();
3088 // Handle initonly fields specially: make a copy and then
3089 // get the address of the copy.
3092 if (FieldInfo.IsInitOnly){
3094 if (ec.IsConstructor){
3095 if (FieldInfo.IsStatic){
3107 local = ig.DeclareLocal (type);
3108 ig.Emit (OpCodes.Stloc, local);
3109 ig.Emit (OpCodes.Ldloca, local);
3114 if (FieldInfo.IsStatic){
3115 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3117 EmitInstance (ec, false);
3118 ig.Emit (OpCodes.Ldflda, FieldInfo);
3124 // A FieldExpr whose address can not be taken
3126 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3127 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3131 public new void AddressOf (EmitContext ec, AddressOp mode)
3133 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3138 /// Expression that evaluates to a Property. The Assign class
3139 /// might set the `Value' expression if we are in an assignment.
3141 /// This is not an LValue because we need to re-write the expression, we
3142 /// can not take data from the stack and store it.
3144 public class PropertyExpr : MemberExpr, IAssignMethod {
3145 public readonly PropertyInfo PropertyInfo;
3148 // This is set externally by the `BaseAccess' class
3151 MethodInfo getter, setter;
3156 LocalTemporary temp;
3159 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3161 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3164 eclass = ExprClass.PropertyAccess;
3168 type = TypeManager.TypeToCoreType (pi.PropertyType);
3170 ResolveAccessors (containerType);
3173 public override string Name {
3175 return PropertyInfo.Name;
3179 public override bool IsInstance {
3185 public override bool IsStatic {
3191 public override Type DeclaringType {
3193 return PropertyInfo.DeclaringType;
3197 public override string GetSignatureForError ()
3199 return TypeManager.GetFullNameSignature (PropertyInfo);
3202 void FindAccessors (Type invocation_type)
3204 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3205 BindingFlags.Static | BindingFlags.Instance |
3206 BindingFlags.DeclaredOnly;
3208 Type current = PropertyInfo.DeclaringType;
3209 for (; current != null; current = current.BaseType) {
3210 MemberInfo[] group = TypeManager.MemberLookup (
3211 invocation_type, invocation_type, current,
3212 MemberTypes.Property, flags, PropertyInfo.Name, null);
3217 if (group.Length != 1)
3218 // Oooops, can this ever happen ?
3221 PropertyInfo pi = (PropertyInfo) group [0];
3224 getter = pi.GetGetMethod (true);
3227 setter = pi.GetSetMethod (true);
3229 MethodInfo accessor = getter != null ? getter : setter;
3231 if (!accessor.IsVirtual)
3237 // We also perform the permission checking here, as the PropertyInfo does not
3238 // hold the information for the accessibility of its setter/getter
3240 // TODO: can use TypeManager.GetProperty to boost performance
3241 void ResolveAccessors (Type containerType)
3243 FindAccessors (containerType);
3245 if (getter != null) {
3246 IMethodData md = TypeManager.GetMethod (getter);
3248 md.SetMemberIsUsed ();
3250 AccessorTable [getter] = PropertyInfo;
3251 is_static = getter.IsStatic;
3254 if (setter != null) {
3255 IMethodData md = TypeManager.GetMethod (setter);
3257 md.SetMemberIsUsed ();
3259 AccessorTable [setter] = PropertyInfo;
3260 is_static = setter.IsStatic;
3264 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3267 InstanceExpression = null;
3271 if (InstanceExpression == null) {
3272 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3276 if (lvalue_instance)
3277 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3279 InstanceExpression = InstanceExpression.DoResolve (ec);
3280 if (InstanceExpression == null)
3283 InstanceExpression.CheckMarshalByRefAccess ();
3285 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3286 InstanceExpression.Type != ec.ContainerType &&
3287 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3288 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3289 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3296 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3298 // TODO: correctly we should compare arguments but it will lead to bigger changes
3299 if (mi is MethodBuilder) {
3300 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3304 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3306 ParameterData iparams = TypeManager.GetParameterData (mi);
3307 sig.Append (getter ? "get_" : "set_");
3309 sig.Append (iparams.GetSignatureForError ());
3311 Report.SymbolRelatedToPreviousError (mi);
3312 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3313 Name, sig.ToString ());
3316 override public Expression DoResolve (EmitContext ec)
3321 if (getter != null){
3322 if (TypeManager.GetParameterData (getter).Count != 0){
3323 Error_PropertyNotFound (getter, true);
3328 if (getter == null){
3330 // The following condition happens if the PropertyExpr was
3331 // created, but is invalid (ie, the property is inaccessible),
3332 // and we did not want to embed the knowledge about this in
3333 // the caller routine. This only avoids double error reporting.
3338 if (InstanceExpression != EmptyExpression.Null) {
3339 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3340 TypeManager.GetFullNameSignature (PropertyInfo));
3345 bool must_do_cs1540_check = false;
3346 if (getter != null &&
3347 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3348 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3349 if (pm != null && pm.HasCustomAccessModifier) {
3350 Report.SymbolRelatedToPreviousError (pm);
3351 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3352 TypeManager.CSharpSignature (getter));
3355 Report.SymbolRelatedToPreviousError (getter);
3356 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3361 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3365 // Only base will allow this invocation to happen.
3367 if (IsBase && getter.IsAbstract) {
3368 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3372 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3382 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3384 if (right_side == EmptyExpression.OutAccess) {
3385 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3386 GetSignatureForError ());
3390 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3391 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3392 GetSignatureForError ());
3396 if (setter == null){
3398 // The following condition happens if the PropertyExpr was
3399 // created, but is invalid (ie, the property is inaccessible),
3400 // and we did not want to embed the knowledge about this in
3401 // the caller routine. This only avoids double error reporting.
3405 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3406 GetSignatureForError ());
3410 if (TypeManager.GetParameterData (setter).Count != 1){
3411 Error_PropertyNotFound (setter, false);
3415 bool must_do_cs1540_check;
3416 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3417 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3418 if (pm != null && pm.HasCustomAccessModifier) {
3419 Report.SymbolRelatedToPreviousError (pm);
3420 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3421 TypeManager.CSharpSignature (setter));
3424 Report.SymbolRelatedToPreviousError (setter);
3425 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3430 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3434 // Only base will allow this invocation to happen.
3436 if (IsBase && setter.IsAbstract){
3437 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3444 public override void Emit (EmitContext ec)
3449 public void Emit (EmitContext ec, bool leave_copy)
3452 // Special case: length of single dimension array property is turned into ldlen
3454 if ((getter == TypeManager.system_int_array_get_length) ||
3455 (getter == TypeManager.int_array_get_length)){
3456 Type iet = InstanceExpression.Type;
3459 // System.Array.Length can be called, but the Type does not
3460 // support invoking GetArrayRank, so test for that case first
3462 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3464 EmitInstance (ec, false);
3465 ec.ig.Emit (OpCodes.Ldlen);
3466 ec.ig.Emit (OpCodes.Conv_I4);
3471 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3474 ec.ig.Emit (OpCodes.Dup);
3476 temp = new LocalTemporary (this.Type);
3483 // Implements the IAssignMethod interface for assignments
3485 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3487 Expression my_source = source;
3489 prepared = prepare_for_load;
3494 ec.ig.Emit (OpCodes.Dup);
3496 temp = new LocalTemporary (this.Type);
3500 } else if (leave_copy) {
3503 temp = new LocalTemporary (this.Type);
3509 ArrayList args = new ArrayList (1);
3510 args.Add (new Argument (my_source, Argument.AType.Expression));
3512 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3520 /// Fully resolved expression that evaluates to an Event
3522 public class EventExpr : MemberExpr {
3523 public readonly EventInfo EventInfo;
3526 MethodInfo add_accessor, remove_accessor;
3528 public EventExpr (EventInfo ei, Location loc)
3532 eclass = ExprClass.EventAccess;
3534 add_accessor = TypeManager.GetAddMethod (ei);
3535 remove_accessor = TypeManager.GetRemoveMethod (ei);
3537 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3540 if (EventInfo is MyEventBuilder){
3541 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3542 type = eb.EventType;
3545 type = EventInfo.EventHandlerType;
3548 public override string Name {
3550 return EventInfo.Name;
3554 public override bool IsInstance {
3560 public override bool IsStatic {
3566 public override Type DeclaringType {
3568 return EventInfo.DeclaringType;
3572 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3573 SimpleName original)
3576 // If the event is local to this class, we transform ourselves into a FieldExpr
3579 if (EventInfo.DeclaringType == ec.ContainerType ||
3580 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3581 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3584 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3587 Report.Error (-200, loc, "Internal error!!");
3591 InstanceExpression = null;
3593 return ml.ResolveMemberAccess (ec, left, loc, original);
3597 return base.ResolveMemberAccess (ec, left, loc, original);
3601 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3604 InstanceExpression = null;
3608 if (InstanceExpression == null) {
3609 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3613 InstanceExpression = InstanceExpression.DoResolve (ec);
3614 if (InstanceExpression == null)
3618 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3619 // However, in the Event case, we reported a CS0122 instead.
3621 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3622 InstanceExpression.Type != ec.ContainerType &&
3623 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3624 Report.SymbolRelatedToPreviousError (EventInfo);
3625 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3632 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3634 return DoResolve (ec);
3637 public override Expression DoResolve (EmitContext ec)
3639 bool must_do_cs1540_check;
3640 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3641 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3642 Report.SymbolRelatedToPreviousError (EventInfo);
3643 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3647 if (!InstanceResolve (ec, must_do_cs1540_check))
3653 public override void Emit (EmitContext ec)
3655 if (InstanceExpression is This)
3656 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3658 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3659 "(except on the defining type)", Name);
3662 public override string GetSignatureForError ()
3664 return TypeManager.CSharpSignature (EventInfo);
3667 public void EmitAddOrRemove (EmitContext ec, Expression source)
3669 BinaryDelegate source_del = (BinaryDelegate) source;
3670 Expression handler = source_del.Right;
3672 Argument arg = new Argument (handler, Argument.AType.Expression);
3673 ArrayList args = new ArrayList ();
3677 if (source_del.IsAddition)
3678 Invocation.EmitCall (
3679 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3681 Invocation.EmitCall (
3682 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3687 public class TemporaryVariable : Expression, IMemoryLocation
3691 public TemporaryVariable (Type type, Location loc)
3695 eclass = ExprClass.Value;
3698 public override Expression DoResolve (EmitContext ec)
3703 TypeExpr te = new TypeExpression (type, loc);
3704 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
3705 if (!li.Resolve (ec))
3708 AnonymousContainer am = ec.CurrentAnonymousMethod;
3709 if ((am != null) && am.IsIterator)
3710 ec.CaptureVariable (li);
3715 public override void Emit (EmitContext ec)
3717 ILGenerator ig = ec.ig;
3719 if (li.FieldBuilder != null) {
3720 ig.Emit (OpCodes.Ldarg_0);
3721 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
3723 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
3727 public void EmitLoadAddress (EmitContext ec)
3729 ILGenerator ig = ec.ig;
3731 if (li.FieldBuilder != null) {
3732 ig.Emit (OpCodes.Ldarg_0);
3733 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
3735 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
3739 public void Store (EmitContext ec, Expression right_side)
3741 if (li.FieldBuilder != null)
3742 ec.ig.Emit (OpCodes.Ldarg_0);
3744 right_side.Emit (ec);
3745 if (li.FieldBuilder != null) {
3746 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
3748 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
3752 public void EmitThis (EmitContext ec)
3754 if (li.FieldBuilder != null) {
3755 ec.ig.Emit (OpCodes.Ldarg_0);
3759 public void EmitStore (ILGenerator ig)
3761 if (li.FieldBuilder != null)
3762 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
3764 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
3767 public void AddressOf (EmitContext ec, AddressOp mode)
3769 EmitLoadAddress (ec);