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 protected void Error_CannotAssign (string to, string roContext)
298 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
302 public static void Error_VoidInvalidInTheContext (Location loc)
304 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
307 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
309 if (Type.Name == target.Name){
310 Report.ExtraInformation (loc,
312 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
313 Type.Name, Type.Assembly.FullName, target.Assembly.FullName));
318 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
319 GetSignatureForError (), TypeManager.CSharpName (target));
323 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
324 bool b = Convert.ExplicitNumericConversion (e, target) != null;
326 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
327 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
328 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
332 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
333 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
334 GetSignatureForError (), TypeManager.CSharpName (target));
338 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
339 Type == TypeManager.anonymous_method_type ?
340 "anonymous method" : "`" + GetSignatureForError () + "'",
341 TypeManager.CSharpName (target));
344 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
346 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
347 TypeManager.CSharpName (type), name);
350 ResolveFlags ExprClassToResolveFlags
355 case ExprClass.Namespace:
356 return ResolveFlags.Type;
358 case ExprClass.MethodGroup:
359 return ResolveFlags.MethodGroup;
361 case ExprClass.Value:
362 case ExprClass.Variable:
363 case ExprClass.PropertyAccess:
364 case ExprClass.EventAccess:
365 case ExprClass.IndexerAccess:
366 return ResolveFlags.VariableOrValue;
369 throw new Exception ("Expression " + GetType () +
370 " ExprClass is Invalid after resolve");
376 /// Resolves an expression and performs semantic analysis on it.
380 /// Currently Resolve wraps DoResolve to perform sanity
381 /// checking and assertion checking on what we expect from Resolve.
383 public Expression Resolve (EmitContext ec, ResolveFlags flags)
385 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
386 return ResolveAsTypeStep (ec, false);
388 bool do_flow_analysis = ec.DoFlowAnalysis;
389 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
390 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
391 do_flow_analysis = false;
392 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
393 omit_struct_analysis = true;
396 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
397 if (this is SimpleName) {
398 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
399 e = ((SimpleName) this).DoResolve (ec, intermediate);
408 if ((flags & e.ExprClassToResolveFlags) == 0) {
409 e.Error_UnexpectedKind (flags, loc);
413 if (e.type == null && !(e is Namespace)) {
414 throw new Exception (
415 "Expression " + e.GetType () +
416 " did not set its type after Resolve\n" +
417 "called from: " + this.GetType ());
424 /// Resolves an expression and performs semantic analysis on it.
426 public Expression Resolve (EmitContext ec)
428 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
430 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
431 ((MethodGroupExpr) e).ReportUsageError ();
437 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
439 Expression e = Resolve (ec);
443 Constant c = e as Constant;
447 Type constant_type = null;
448 if (mc is MemberBase) {
449 constant_type = ((MemberBase)mc).MemberType;
452 Const.Error_ExpressionMustBeConstant (constant_type, loc, mc.GetSignatureForError ());
457 /// Resolves an expression for LValue assignment
461 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
462 /// checking and assertion checking on what we expect from Resolve
464 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
466 int errors = Report.Errors;
467 bool out_access = right_side == EmptyExpression.OutAccess;
469 Expression e = DoResolveLValue (ec, right_side);
471 if (e != null && out_access && !(e is IMemoryLocation)) {
472 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
473 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
475 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
476 // e.GetType () + " " + e.GetSignatureForError ());
481 if (errors == Report.Errors) {
483 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
485 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
490 if (e.eclass == ExprClass.Invalid)
491 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
493 if (e.eclass == ExprClass.MethodGroup) {
494 ((MethodGroupExpr) e).ReportUsageError ();
499 throw new Exception ("Expression " + e + " did not set its type after Resolve");
505 /// Emits the code for the expression
509 /// The Emit method is invoked to generate the code
510 /// for the expression.
512 public abstract void Emit (EmitContext ec);
514 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
517 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
521 /// Protected constructor. Only derivate types should
522 /// be able to be created
525 protected Expression ()
527 eclass = ExprClass.Invalid;
532 /// Returns a literalized version of a literal FieldInfo
536 /// The possible return values are:
537 /// IntConstant, UIntConstant
538 /// LongLiteral, ULongConstant
539 /// FloatConstant, DoubleConstant
542 /// The value returned is already resolved.
544 public static Constant Constantify (object v, Type t)
546 if (t == TypeManager.int32_type)
547 return new IntConstant ((int) v, Location.Null);
548 else if (t == TypeManager.uint32_type)
549 return new UIntConstant ((uint) v, Location.Null);
550 else if (t == TypeManager.int64_type)
551 return new LongConstant ((long) v, Location.Null);
552 else if (t == TypeManager.uint64_type)
553 return new ULongConstant ((ulong) v, Location.Null);
554 else if (t == TypeManager.float_type)
555 return new FloatConstant ((float) v, Location.Null);
556 else if (t == TypeManager.double_type)
557 return new DoubleConstant ((double) v, Location.Null);
558 else if (t == TypeManager.string_type)
559 return new StringConstant ((string) v, Location.Null);
560 else if (t == TypeManager.short_type)
561 return new ShortConstant ((short)v, Location.Null);
562 else if (t == TypeManager.ushort_type)
563 return new UShortConstant ((ushort)v, Location.Null);
564 else if (t == TypeManager.sbyte_type)
565 return new SByteConstant ((sbyte)v, Location.Null);
566 else if (t == TypeManager.byte_type)
567 return new ByteConstant ((byte)v, Location.Null);
568 else if (t == TypeManager.char_type)
569 return new CharConstant ((char)v, Location.Null);
570 else if (t == TypeManager.bool_type)
571 return new BoolConstant ((bool) v, Location.Null);
572 else if (t == TypeManager.decimal_type)
573 return new DecimalConstant ((decimal) v, Location.Null);
574 else if (TypeManager.IsEnumType (t)){
575 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
577 real_type = System.Enum.GetUnderlyingType (real_type);
579 Constant e = Constantify (v, real_type);
581 return new EnumConstant (e, t);
582 } else if (v == null && !TypeManager.IsValueType (t))
583 return new NullLiteral (Location.Null);
585 throw new Exception ("Unknown type for constant (" + t +
590 /// Returns a fully formed expression after a MemberLookup
593 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
596 return new EventExpr ((EventInfo) mi, loc);
597 else if (mi is FieldInfo)
598 return new FieldExpr ((FieldInfo) mi, loc);
599 else if (mi is PropertyInfo)
600 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
601 else if (mi is Type){
602 return new TypeExpression ((System.Type) mi, loc);
608 protected static ArrayList almostMatchedMembers = new ArrayList (4);
611 // FIXME: Probably implement a cache for (t,name,current_access_set)?
613 // This code could use some optimizations, but we need to do some
614 // measurements. For example, we could use a delegate to `flag' when
615 // something can not any longer be a method-group (because it is something
619 // If the return value is an Array, then it is an array of
622 // If the return value is an MemberInfo, it is anything, but a Method
626 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
627 // the arguments here and have MemberLookup return only the methods that
628 // match the argument count/type, unlike we are doing now (we delay this
631 // This is so we can catch correctly attempts to invoke instance methods
632 // from a static body (scan for error 120 in ResolveSimpleName).
635 // FIXME: Potential optimization, have a static ArrayList
638 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
639 MemberTypes mt, BindingFlags bf, Location loc)
641 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
645 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
646 // `qualifier_type' or null to lookup members in the current class.
649 public static Expression MemberLookup (Type container_type,
650 Type qualifier_type, Type queried_type,
651 string name, MemberTypes mt,
652 BindingFlags bf, Location loc)
654 almostMatchedMembers.Clear ();
656 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
657 queried_type, mt, bf, name, almostMatchedMembers);
663 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
664 MemberInfo non_method = null;
665 ArrayList methods = new ArrayList (2);
667 foreach (MemberInfo m in mi) {
668 if (m is MethodBase) {
673 if (non_method == null) {
681 Report.SymbolRelatedToPreviousError (m);
682 Report.SymbolRelatedToPreviousError (non_method);
683 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
684 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
688 if (non_method != null && is_interface) {
689 MethodBase method = (MethodBase)methods[0];
690 Report.SymbolRelatedToPreviousError (method);
691 Report.SymbolRelatedToPreviousError (non_method);
692 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
693 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
696 if (methods.Count == 0)
697 return new MethodGroupExpr (mi, loc);
699 return new MethodGroupExpr (methods, loc);
702 if (mi [0] is MethodBase)
703 return new MethodGroupExpr (mi, loc);
705 return ExprClassFromMemberInfo (container_type, mi [0], loc);
708 public const MemberTypes AllMemberTypes =
709 MemberTypes.Constructor |
713 MemberTypes.NestedType |
714 MemberTypes.Property;
716 public const BindingFlags AllBindingFlags =
717 BindingFlags.Public |
718 BindingFlags.Static |
719 BindingFlags.Instance;
721 public static Expression MemberLookup (Type container_type, Type queried_type,
722 string name, Location loc)
724 return MemberLookup (container_type, null, queried_type, name,
725 AllMemberTypes, AllBindingFlags, loc);
728 public static Expression MemberLookup (Type container_type, Type qualifier_type,
729 Type queried_type, string name, Location loc)
731 return MemberLookup (container_type, qualifier_type, queried_type,
732 name, AllMemberTypes, AllBindingFlags, loc);
735 public static Expression MethodLookup (EmitContext ec, Type queried_type,
736 string name, Location loc)
738 return MemberLookup (ec.ContainerType, null, queried_type, name,
739 MemberTypes.Method, AllBindingFlags, loc);
743 /// This is a wrapper for MemberLookup that is not used to "probe", but
744 /// to find a final definition. If the final definition is not found, we
745 /// look for private members and display a useful debugging message if we
748 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
749 Type queried_type, string name, Location loc)
751 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
752 AllMemberTypes, AllBindingFlags, loc);
755 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
756 Type queried_type, string name,
757 MemberTypes mt, BindingFlags bf,
762 int errors = Report.Errors;
764 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
766 if (e == null && errors == Report.Errors)
767 // No errors were reported by MemberLookup, but there was an error.
768 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
773 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
774 Type queried_type, string name,
775 string class_name, bool complain_if_none_found,
778 if (almostMatchedMembers.Count != 0) {
779 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
780 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
781 for (int j = 0; j < i; ++j) {
782 if (m == almostMatchedMembers [j]) {
790 Type declaring_type = m.DeclaringType;
792 Report.SymbolRelatedToPreviousError (m);
793 if (qualifier_type == null) {
794 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
795 TypeManager.CSharpName (m.DeclaringType),
796 TypeManager.CSharpName (container_type));
798 } else if (qualifier_type != container_type &&
799 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
800 // Although a derived class can access protected members of
801 // its base class it cannot do so through an instance of the
802 // base class (CS1540). If the qualifier_type is a base of the
803 // ec.ContainerType and the lookup succeeds with the latter one,
804 // then we are in this situation.
805 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
807 Report.SymbolRelatedToPreviousError (m);
808 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
811 almostMatchedMembers.Clear ();
815 MemberInfo[] lookup = null;
816 if (queried_type == null) {
817 class_name = "global::";
819 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
820 AllMemberTypes, AllBindingFlags |
821 BindingFlags.NonPublic, name, null);
824 if (lookup == null) {
825 if (!complain_if_none_found)
828 if (class_name != null)
829 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
832 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
836 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
837 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
838 if (name == ".ctor" && ml.Count == 0)
840 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
844 Report.SymbolRelatedToPreviousError (lookup [0]);
845 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
849 /// Returns an expression that can be used to invoke operator true
850 /// on the expression if it exists.
852 static public StaticCallExpr GetOperatorTrue (EmitContext ec, Expression e, Location loc)
854 return GetOperatorTrueOrFalse (ec, e, true, loc);
858 /// Returns an expression that can be used to invoke operator false
859 /// on the expression if it exists.
861 static public StaticCallExpr GetOperatorFalse (EmitContext ec, Expression e, Location loc)
863 return GetOperatorTrueOrFalse (ec, e, false, loc);
866 static StaticCallExpr GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
869 Expression operator_group;
871 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
872 if (operator_group == null)
875 ArrayList arguments = new ArrayList ();
876 arguments.Add (new Argument (e, Argument.AType.Expression));
877 method = Invocation.OverloadResolve (
878 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
883 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
887 /// Resolves the expression `e' into a boolean expression: either through
888 /// an implicit conversion, or through an `operator true' invocation
890 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
896 if (e.Type == TypeManager.bool_type)
899 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
901 if (converted != null)
905 // If no implicit conversion to bool exists, try using `operator true'
907 converted = Expression.GetOperatorTrue (ec, e, loc);
908 if (converted == null){
909 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
915 public virtual string ExprClassName
919 case ExprClass.Invalid:
921 case ExprClass.Value:
923 case ExprClass.Variable:
925 case ExprClass.Namespace:
929 case ExprClass.MethodGroup:
930 return "method group";
931 case ExprClass.PropertyAccess:
932 return "property access";
933 case ExprClass.EventAccess:
934 return "event access";
935 case ExprClass.IndexerAccess:
936 return "indexer access";
937 case ExprClass.Nothing:
940 throw new Exception ("Should not happen");
945 /// Reports that we were expecting `expr' to be of class `expected'
947 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
949 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
952 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
954 string name = GetSignatureForError ();
956 name = ds.GetSignatureForError () + '.' + name;
958 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
959 name, was, expected);
962 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
964 string [] valid = new string [4];
967 if ((flags & ResolveFlags.VariableOrValue) != 0) {
968 valid [count++] = "variable";
969 valid [count++] = "value";
972 if ((flags & ResolveFlags.Type) != 0)
973 valid [count++] = "type";
975 if ((flags & ResolveFlags.MethodGroup) != 0)
976 valid [count++] = "method group";
979 valid [count++] = "unknown";
981 StringBuilder sb = new StringBuilder (valid [0]);
982 for (int i = 1; i < count - 1; i++) {
984 sb.Append (valid [i]);
987 sb.Append ("' or `");
988 sb.Append (valid [count - 1]);
991 Report.Error (119, loc,
992 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
995 public static void UnsafeError (Location loc)
997 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1001 // Load the object from the pointer.
1003 public static void LoadFromPtr (ILGenerator ig, Type t)
1005 if (t == TypeManager.int32_type)
1006 ig.Emit (OpCodes.Ldind_I4);
1007 else if (t == TypeManager.uint32_type)
1008 ig.Emit (OpCodes.Ldind_U4);
1009 else if (t == TypeManager.short_type)
1010 ig.Emit (OpCodes.Ldind_I2);
1011 else if (t == TypeManager.ushort_type)
1012 ig.Emit (OpCodes.Ldind_U2);
1013 else if (t == TypeManager.char_type)
1014 ig.Emit (OpCodes.Ldind_U2);
1015 else if (t == TypeManager.byte_type)
1016 ig.Emit (OpCodes.Ldind_U1);
1017 else if (t == TypeManager.sbyte_type)
1018 ig.Emit (OpCodes.Ldind_I1);
1019 else if (t == TypeManager.uint64_type)
1020 ig.Emit (OpCodes.Ldind_I8);
1021 else if (t == TypeManager.int64_type)
1022 ig.Emit (OpCodes.Ldind_I8);
1023 else if (t == TypeManager.float_type)
1024 ig.Emit (OpCodes.Ldind_R4);
1025 else if (t == TypeManager.double_type)
1026 ig.Emit (OpCodes.Ldind_R8);
1027 else if (t == TypeManager.bool_type)
1028 ig.Emit (OpCodes.Ldind_I1);
1029 else if (t == TypeManager.intptr_type)
1030 ig.Emit (OpCodes.Ldind_I);
1031 else if (TypeManager.IsEnumType (t)) {
1032 if (t == TypeManager.enum_type)
1033 ig.Emit (OpCodes.Ldind_Ref);
1035 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1036 } else if (t.IsValueType)
1037 ig.Emit (OpCodes.Ldobj, t);
1038 else if (t.IsPointer)
1039 ig.Emit (OpCodes.Ldind_I);
1041 ig.Emit (OpCodes.Ldind_Ref);
1045 // The stack contains the pointer and the value of type `type'
1047 public static void StoreFromPtr (ILGenerator ig, Type type)
1049 if (TypeManager.IsEnumType (type))
1050 type = TypeManager.EnumToUnderlying (type);
1051 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1052 ig.Emit (OpCodes.Stind_I4);
1053 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1054 ig.Emit (OpCodes.Stind_I8);
1055 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1056 type == TypeManager.ushort_type)
1057 ig.Emit (OpCodes.Stind_I2);
1058 else if (type == TypeManager.float_type)
1059 ig.Emit (OpCodes.Stind_R4);
1060 else if (type == TypeManager.double_type)
1061 ig.Emit (OpCodes.Stind_R8);
1062 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1063 type == TypeManager.bool_type)
1064 ig.Emit (OpCodes.Stind_I1);
1065 else if (type == TypeManager.intptr_type)
1066 ig.Emit (OpCodes.Stind_I);
1067 else if (type.IsValueType)
1068 ig.Emit (OpCodes.Stobj, type);
1070 ig.Emit (OpCodes.Stind_Ref);
1074 // Returns the size of type `t' if known, otherwise, 0
1076 public static int GetTypeSize (Type t)
1078 t = TypeManager.TypeToCoreType (t);
1079 if (t == TypeManager.int32_type ||
1080 t == TypeManager.uint32_type ||
1081 t == TypeManager.float_type)
1083 else if (t == TypeManager.int64_type ||
1084 t == TypeManager.uint64_type ||
1085 t == TypeManager.double_type)
1087 else if (t == TypeManager.byte_type ||
1088 t == TypeManager.sbyte_type ||
1089 t == TypeManager.bool_type)
1091 else if (t == TypeManager.short_type ||
1092 t == TypeManager.char_type ||
1093 t == TypeManager.ushort_type)
1095 else if (t == TypeManager.decimal_type)
1101 public static void Error_NegativeArrayIndex (Location loc)
1103 Report.Error (248, loc, "Cannot create an array with a negative size");
1106 protected void Error_CannotCallAbstractBase (string name)
1108 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1112 // Converts `source' to an int, uint, long or ulong.
1114 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1118 using (ec.With (EmitContext.Flags.CheckState, true)) {
1119 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1121 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1123 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1125 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1127 if (target == null) {
1128 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1134 // Only positive constants are allowed at compile time
1136 if (target is Constant){
1137 if (target is IntConstant){
1138 if (((IntConstant) target).Value < 0){
1139 Error_NegativeArrayIndex (loc);
1144 if (target is LongConstant){
1145 if (((LongConstant) target).Value < 0){
1146 Error_NegativeArrayIndex (loc);
1159 /// This is just a base class for expressions that can
1160 /// appear on statements (invocations, object creation,
1161 /// assignments, post/pre increment and decrement). The idea
1162 /// being that they would support an extra Emition interface that
1163 /// does not leave a result on the stack.
1165 public abstract class ExpressionStatement : Expression {
1167 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1169 Expression e = Resolve (ec);
1173 ExpressionStatement es = e as ExpressionStatement;
1175 Error (201, "Only assignment, call, increment, decrement and new object " +
1176 "expressions can be used as a statement");
1182 /// Requests the expression to be emitted in a `statement'
1183 /// context. This means that no new value is left on the
1184 /// stack after invoking this method (constrasted with
1185 /// Emit that will always leave a value on the stack).
1187 public abstract void EmitStatement (EmitContext ec);
1191 /// This kind of cast is used to encapsulate the child
1192 /// whose type is child.Type into an expression that is
1193 /// reported to return "return_type". This is used to encapsulate
1194 /// expressions which have compatible types, but need to be dealt
1195 /// at higher levels with.
1197 /// For example, a "byte" expression could be encapsulated in one
1198 /// of these as an "unsigned int". The type for the expression
1199 /// would be "unsigned int".
1202 public class EmptyCast : Expression {
1203 protected readonly Expression child;
1205 public EmptyCast (Expression child, Type return_type)
1207 eclass = child.eclass;
1208 loc = child.Location;
1213 public override Expression DoResolve (EmitContext ec)
1215 // This should never be invoked, we are born in fully
1216 // initialized state.
1221 public override void Emit (EmitContext ec)
1226 public override bool GetAttributableValue (Type valueType, out object value)
1228 return child.GetAttributableValue (valueType, out value);
1233 /// This is a numeric cast to a Decimal
1235 public class CastToDecimal : EmptyCast {
1237 MethodInfo conversion_operator;
1239 public CastToDecimal (Expression child)
1240 : this (child, false)
1244 public CastToDecimal (Expression child, bool find_explicit)
1245 : base (child, TypeManager.decimal_type)
1247 conversion_operator = GetConversionOperator (find_explicit);
1249 if (conversion_operator == null)
1250 throw new InternalErrorException ("Outer conversion routine is out of sync");
1253 // Returns the implicit operator that converts from
1254 // 'child.Type' to System.Decimal.
1255 MethodInfo GetConversionOperator (bool find_explicit)
1257 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1259 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1260 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1262 foreach (MethodInfo oper in mi) {
1263 ParameterData pd = TypeManager.GetParameterData (oper);
1265 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1271 public override void Emit (EmitContext ec)
1273 ILGenerator ig = ec.ig;
1276 ig.Emit (OpCodes.Call, conversion_operator);
1281 /// This is an explicit numeric cast from a Decimal
1283 public class CastFromDecimal : EmptyCast
1285 static IDictionary operators;
1287 public CastFromDecimal (Expression child, Type return_type)
1288 : base (child, return_type)
1290 if (child.Type != TypeManager.decimal_type)
1291 throw new InternalErrorException (
1292 "The expected type is Decimal, instead it is " + child.Type.FullName);
1295 // Returns the explicit operator that converts from an
1296 // express of type System.Decimal to 'type'.
1297 public Expression Resolve ()
1299 if (operators == null) {
1300 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1301 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1302 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1304 operators = new System.Collections.Specialized.HybridDictionary ();
1305 foreach (MethodInfo oper in all_oper) {
1306 ParameterData pd = TypeManager.GetParameterData (oper);
1307 if (pd.ParameterType (0) == TypeManager.decimal_type)
1308 operators.Add (oper.ReturnType, oper);
1312 return operators.Contains (type) ? this : null;
1315 public override void Emit (EmitContext ec)
1317 ILGenerator ig = ec.ig;
1320 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1325 // We need to special case this since an empty cast of
1326 // a NullLiteral is still a Constant
1328 public class NullCast : Constant {
1329 public Constant child;
1331 public NullCast (Constant child, Type return_type):
1332 base (Location.Null)
1334 eclass = child.eclass;
1339 override public string AsString ()
1344 public override object GetValue ()
1349 public override Expression DoResolve (EmitContext ec)
1351 // This should never be invoked, we are born in fully
1352 // initialized state.
1357 public override void Emit (EmitContext ec)
1362 public override Constant Increment ()
1364 throw new NotSupportedException ();
1367 public override bool IsDefaultValue {
1373 public override bool IsNegative {
1379 public override Constant Reduce (bool inCheckedContext, Type target_type)
1381 if (type == target_type)
1382 return child.Reduce (inCheckedContext, target_type);
1391 /// This class is used to wrap literals which belong inside Enums
1393 public class EnumConstant : Constant {
1394 public Constant Child;
1396 public EnumConstant (Constant child, Type enum_type):
1397 base (child.Location)
1399 eclass = child.eclass;
1404 public override Expression DoResolve (EmitContext ec)
1406 // This should never be invoked, we are born in fully
1407 // initialized state.
1412 public override void Emit (EmitContext ec)
1417 public override bool GetAttributableValue (Type valueType, out object value)
1419 value = GetTypedValue ();
1423 public override string GetSignatureForError()
1425 return TypeManager.CSharpName (Type);
1428 public override object GetValue ()
1430 return Child.GetValue ();
1433 public override object GetTypedValue ()
1435 // FIXME: runtime is not ready to work with just emited enums
1436 if (!RootContext.StdLib) {
1437 return Child.GetValue ();
1440 return System.Enum.ToObject (type, Child.GetValue ());
1443 public override string AsString ()
1445 return Child.AsString ();
1448 public override DoubleConstant ConvertToDouble ()
1450 return Child.ConvertToDouble ();
1453 public override FloatConstant ConvertToFloat ()
1455 return Child.ConvertToFloat ();
1458 public override ULongConstant ConvertToULong ()
1460 return Child.ConvertToULong ();
1463 public override LongConstant ConvertToLong ()
1465 return Child.ConvertToLong ();
1468 public override UIntConstant ConvertToUInt ()
1470 return Child.ConvertToUInt ();
1473 public override IntConstant ConvertToInt ()
1475 return Child.ConvertToInt ();
1478 public override Constant Increment()
1480 return new EnumConstant (Child.Increment (), type);
1483 public override bool IsDefaultValue {
1485 return Child.IsDefaultValue;
1489 public override bool IsZeroInteger {
1490 get { return Child.IsZeroInteger; }
1493 public override bool IsNegative {
1495 return Child.IsNegative;
1499 public override Constant Reduce(bool inCheckedContext, Type target_type)
1501 if (Child.Type == target_type)
1504 return Child.Reduce (inCheckedContext, target_type);
1507 public override Constant ToType (Type type, Location loc)
1510 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1511 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1514 if (type.UnderlyingSystemType != Child.Type)
1515 Child = Child.ToType (type.UnderlyingSystemType, loc);
1519 if (!Convert.ImplicitStandardConversionExists (this, type)){
1520 Error_ValueCannotBeConverted (loc, type, false);
1524 return Child.ToType (type, loc);
1530 /// This kind of cast is used to encapsulate Value Types in objects.
1532 /// The effect of it is to box the value type emitted by the previous
1535 public class BoxedCast : EmptyCast {
1537 public BoxedCast (Expression expr, Type target_type)
1538 : base (expr, target_type)
1540 eclass = ExprClass.Value;
1543 public override Expression DoResolve (EmitContext ec)
1545 // This should never be invoked, we are born in fully
1546 // initialized state.
1551 public override void Emit (EmitContext ec)
1555 ec.ig.Emit (OpCodes.Box, child.Type);
1559 public class UnboxCast : EmptyCast {
1560 public UnboxCast (Expression expr, Type return_type)
1561 : base (expr, return_type)
1565 public override Expression DoResolve (EmitContext ec)
1567 // This should never be invoked, we are born in fully
1568 // initialized state.
1573 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1575 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1576 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1577 return base.DoResolveLValue (ec, right_side);
1580 public override void Emit (EmitContext ec)
1583 ILGenerator ig = ec.ig;
1586 ig.Emit (OpCodes.Unbox, t);
1588 LoadFromPtr (ig, t);
1593 /// This is used to perform explicit numeric conversions.
1595 /// Explicit numeric conversions might trigger exceptions in a checked
1596 /// context, so they should generate the conv.ovf opcodes instead of
1599 public class ConvCast : EmptyCast {
1600 public enum Mode : byte {
1601 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1603 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1604 U2_I1, U2_U1, U2_I2, U2_CH,
1605 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1606 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1607 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1608 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1609 CH_I1, CH_U1, CH_I2,
1610 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1611 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1616 public ConvCast (Expression child, Type return_type, Mode m)
1617 : base (child, return_type)
1622 public override Expression DoResolve (EmitContext ec)
1624 // This should never be invoked, we are born in fully
1625 // initialized state.
1630 public override string ToString ()
1632 return String.Format ("ConvCast ({0}, {1})", mode, child);
1635 public override void Emit (EmitContext ec)
1637 ILGenerator ig = ec.ig;
1643 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1644 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1645 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1646 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1647 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1649 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1650 case Mode.U1_CH: /* nothing */ break;
1652 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1653 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1654 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1655 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1656 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1657 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1659 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1660 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1661 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1662 case Mode.U2_CH: /* nothing */ break;
1664 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1665 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1666 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1667 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1668 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1669 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1670 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1672 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1673 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1674 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1675 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1676 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1677 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1679 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1680 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1681 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1682 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1683 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1684 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1685 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1686 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1688 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1689 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1690 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1691 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1692 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1693 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1694 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1695 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1697 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1698 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1699 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1701 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1702 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1703 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1704 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1705 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1706 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1707 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1708 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1709 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1711 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1712 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1713 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1714 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1715 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1716 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1717 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1718 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1719 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1720 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1724 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1725 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1726 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1727 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1728 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1730 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1731 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1733 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1734 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1735 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1736 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1737 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1738 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1740 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1741 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1742 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1743 case Mode.U2_CH: /* nothing */ break;
1745 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1746 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1747 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1748 case Mode.I4_U4: /* nothing */ break;
1749 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1750 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1751 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1753 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1754 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1755 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1756 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1757 case Mode.U4_I4: /* nothing */ break;
1758 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1760 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1761 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1762 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1763 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1764 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1765 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1766 case Mode.I8_U8: /* nothing */ break;
1767 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1769 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1770 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1771 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1772 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1773 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1774 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1775 case Mode.U8_I8: /* nothing */ break;
1776 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1778 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1779 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1780 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1782 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1783 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1784 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1785 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1786 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1787 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1788 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1789 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1790 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1792 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1793 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1794 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1795 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1796 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1797 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1798 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1799 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1800 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1801 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1807 public class OpcodeCast : EmptyCast {
1811 public OpcodeCast (Expression child, Type return_type, OpCode op)
1812 : base (child, return_type)
1816 second_valid = false;
1819 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1820 : base (child, return_type)
1825 second_valid = true;
1828 public override Expression DoResolve (EmitContext ec)
1830 // This should never be invoked, we are born in fully
1831 // initialized state.
1836 public override void Emit (EmitContext ec)
1847 /// This kind of cast is used to encapsulate a child and cast it
1848 /// to the class requested
1850 public class ClassCast : EmptyCast {
1851 public ClassCast (Expression child, Type return_type)
1852 : base (child, return_type)
1857 public override Expression DoResolve (EmitContext ec)
1859 // This should never be invoked, we are born in fully
1860 // initialized state.
1865 public override void Emit (EmitContext ec)
1869 ec.ig.Emit (OpCodes.Castclass, type);
1875 /// SimpleName expressions are formed of a single word and only happen at the beginning
1876 /// of a dotted-name.
1878 public class SimpleName : Expression {
1882 public SimpleName (string name, Location l)
1888 public static string RemoveGenericArity (string name)
1893 public SimpleName GetMethodGroup ()
1895 return new SimpleName (RemoveGenericArity (Name), loc);
1898 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1900 if (ec.IsFieldInitializer)
1901 Report.Error (236, l,
1902 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1906 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1910 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1912 return resolved_to != null && resolved_to.Type != null &&
1913 resolved_to.Type.Name == Name &&
1914 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1917 public override Expression DoResolve (EmitContext ec)
1919 return SimpleNameResolve (ec, null, false);
1922 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1924 return SimpleNameResolve (ec, right_side, false);
1928 public Expression DoResolve (EmitContext ec, bool intermediate)
1930 return SimpleNameResolve (ec, null, intermediate);
1933 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
1935 int errors = Report.Errors;
1936 FullNamedExpression fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
1940 if (silent || errors != Report.Errors)
1943 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
1945 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
1949 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
1950 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
1951 foreach (Assembly a in RootNamespace.Global.Assemblies) {
1952 Type type = a.GetType (fullname);
1954 Report.SymbolRelatedToPreviousError (type);
1955 Expression.ErrorIsInaccesible (loc, fullname);
1960 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
1964 // TODO: I am still not convinced about this. If someone else will need it
1965 // implement this as virtual property in MemberCore hierarchy
1966 string GetMemberType (MemberCore mc)
1968 if (mc is PropertyBase)
1972 if (mc is FieldBase)
1974 if (mc is MethodCore)
1976 if (mc is EnumMember)
1982 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
1988 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
1992 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
1999 /// 7.5.2: Simple Names.
2001 /// Local Variables and Parameters are handled at
2002 /// parse time, so they never occur as SimpleNames.
2004 /// The `intermediate' flag is used by MemberAccess only
2005 /// and it is used to inform us that it is ok for us to
2006 /// avoid the static check, because MemberAccess might end
2007 /// up resolving the Name as a Type name and the access as
2008 /// a static type access.
2010 /// ie: Type Type; .... { Type.GetType (""); }
2012 /// Type is both an instance variable and a Type; Type.GetType
2013 /// is the static method not an instance method of type.
2015 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2017 Expression e = null;
2020 // Stage 1: Performed by the parser (binding to locals or parameters).
2022 Block current_block = ec.CurrentBlock;
2023 if (current_block != null){
2024 LocalInfo vi = current_block.GetLocalInfo (Name);
2026 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2027 if (right_side != null) {
2028 return var.ResolveLValue (ec, right_side, loc);
2030 ResolveFlags rf = ResolveFlags.VariableOrValue;
2032 rf |= ResolveFlags.DisableFlowAnalysis;
2033 return var.Resolve (ec, rf);
2037 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2039 if (right_side != null)
2040 return pref.ResolveLValue (ec, right_side, loc);
2042 return pref.Resolve (ec);
2047 // Stage 2: Lookup members
2050 DeclSpace lookup_ds = ec.DeclContainer;
2051 Type almost_matched_type = null;
2052 ArrayList almost_matched = null;
2054 if (lookup_ds.TypeBuilder == null)
2057 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2061 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2062 almost_matched_type = lookup_ds.TypeBuilder;
2063 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2066 lookup_ds =lookup_ds.Parent;
2067 } while (lookup_ds != null);
2069 if (e == null && ec.ContainerType != null)
2070 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2073 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2074 almost_matched_type = ec.ContainerType;
2075 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2077 e = ResolveAsTypeStep (ec, true);
2081 if (almost_matched != null)
2082 almostMatchedMembers = almost_matched;
2083 if (almost_matched_type == null)
2084 almost_matched_type = ec.ContainerType;
2085 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2092 if (e is MemberExpr) {
2093 MemberExpr me = (MemberExpr) e;
2096 if (me.IsInstance) {
2097 if (ec.IsStatic || ec.IsFieldInitializer) {
2099 // Note that an MemberExpr can be both IsInstance and IsStatic.
2100 // An unresolved MethodGroupExpr can contain both kinds of methods
2101 // and each predicate is true if the MethodGroupExpr contains
2102 // at least one of that kind of method.
2106 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2107 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2108 return EmptyExpression.Null;
2112 // Pass the buck to MemberAccess and Invocation.
2114 left = EmptyExpression.Null;
2116 left = ec.GetThis (loc);
2119 left = new TypeExpression (ec.ContainerType, loc);
2122 e = me.ResolveMemberAccess (ec, left, loc, null);
2126 me = e as MemberExpr;
2131 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2132 me.InstanceExpression.Type != me.DeclaringType &&
2133 !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType) &&
2134 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2135 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2136 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2140 return (right_side != null)
2141 ? me.DoResolveLValue (ec, right_side)
2142 : me.DoResolve (ec);
2148 public override void Emit (EmitContext ec)
2151 // If this is ever reached, then we failed to
2152 // find the name as a namespace
2155 Error (103, "The name `" + Name +
2156 "' does not exist in the class `" +
2157 ec.DeclContainer.Name + "'");
2160 public override string ToString ()
2165 public override string GetSignatureForError ()
2172 /// Represents a namespace or a type. The name of the class was inspired by
2173 /// section 10.8.1 (Fully Qualified Names).
2175 public abstract class FullNamedExpression : Expression {
2176 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2181 public abstract string FullName {
2187 /// Expression that evaluates to a type
2189 public abstract class TypeExpr : FullNamedExpression {
2190 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2192 TypeExpr t = DoResolveAsTypeStep (ec);
2196 eclass = ExprClass.Type;
2200 override public Expression DoResolve (EmitContext ec)
2202 return ResolveAsTypeTerminal (ec, false);
2205 override public void Emit (EmitContext ec)
2207 throw new Exception ("Should never be called");
2210 public virtual bool CheckAccessLevel (DeclSpace ds)
2212 return ds.CheckAccessLevel (Type);
2215 public virtual bool AsAccessible (DeclSpace ds, int flags)
2217 return ds.AsAccessible (Type, flags);
2220 public virtual bool IsClass {
2221 get { return Type.IsClass; }
2224 public virtual bool IsValueType {
2225 get { return Type.IsValueType; }
2228 public virtual bool IsInterface {
2229 get { return Type.IsInterface; }
2232 public virtual bool IsSealed {
2233 get { return Type.IsSealed; }
2236 public virtual bool CanInheritFrom ()
2238 if (Type == TypeManager.enum_type ||
2239 (Type == TypeManager.value_type && RootContext.StdLib) ||
2240 Type == TypeManager.multicast_delegate_type ||
2241 Type == TypeManager.delegate_type ||
2242 Type == TypeManager.array_type)
2248 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2250 public abstract string Name {
2254 public override bool Equals (object obj)
2256 TypeExpr tobj = obj as TypeExpr;
2260 return Type == tobj.Type;
2263 public override int GetHashCode ()
2265 return Type.GetHashCode ();
2268 public override string ToString ()
2275 /// Fully resolved Expression that already evaluated to a type
2277 public class TypeExpression : TypeExpr {
2278 public TypeExpression (Type t, Location l)
2281 eclass = ExprClass.Type;
2285 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2290 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2295 public override string Name {
2296 get { return Type.ToString (); }
2299 public override string FullName {
2300 get { return Type.FullName; }
2305 /// Used to create types from a fully qualified name. These are just used
2306 /// by the parser to setup the core types. A TypeLookupExpression is always
2307 /// classified as a type.
2309 public sealed class TypeLookupExpression : TypeExpr {
2310 readonly string name;
2312 public TypeLookupExpression (string name)
2315 eclass = ExprClass.Type;
2318 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2320 // It's null for corlib compilation only
2322 return DoResolveAsTypeStep (ec);
2327 static readonly char [] dot_array = { '.' };
2328 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2330 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2332 string lookup_name = name;
2333 int pos = name.IndexOf ('.');
2335 rest = name.Substring (pos + 1);
2336 lookup_name = name.Substring (0, pos);
2339 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2341 if (resolved != null && rest != null) {
2342 // Now handle the rest of the the name.
2343 string [] elements = rest.Split (dot_array);
2345 int count = elements.Length;
2347 while (i < count && resolved != null && resolved is Namespace) {
2348 Namespace ns = resolved as Namespace;
2349 element = elements [i++];
2350 lookup_name += "." + element;
2351 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2354 if (resolved != null && resolved is TypeExpr) {
2355 Type t = ((TypeExpr) resolved).Type;
2357 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2359 lookup_name = t.FullName;
2366 t = TypeManager.GetNestedType (t, elements [i++]);
2371 if (resolved == null) {
2372 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2376 if (!(resolved is TypeExpr)) {
2377 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2381 type = resolved.Type;
2385 public override string Name {
2386 get { return name; }
2389 public override string FullName {
2390 get { return name; }
2394 public class TypeAliasExpression : TypeExpr {
2397 public TypeAliasExpression (TypeExpr texpr, Location l)
2400 loc = texpr.Location;
2402 eclass = ExprClass.Type;
2405 public override string Name {
2406 get { return texpr.Name; }
2409 public override string FullName {
2410 get { return texpr.FullName; }
2413 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2418 public override bool CheckAccessLevel (DeclSpace ds)
2420 return texpr.CheckAccessLevel (ds);
2423 public override bool AsAccessible (DeclSpace ds, int flags)
2425 return texpr.AsAccessible (ds, flags);
2428 public override bool IsClass {
2429 get { return texpr.IsClass; }
2432 public override bool IsValueType {
2433 get { return texpr.IsValueType; }
2436 public override bool IsInterface {
2437 get { return texpr.IsInterface; }
2440 public override bool IsSealed {
2441 get { return texpr.IsSealed; }
2446 /// This class denotes an expression which evaluates to a member
2447 /// of a struct or a class.
2449 public abstract class MemberExpr : Expression
2452 /// The name of this member.
2454 public abstract string Name {
2459 /// Whether this is an instance member.
2461 public abstract bool IsInstance {
2466 /// Whether this is a static member.
2468 public abstract bool IsStatic {
2473 /// The type which declares this member.
2475 public abstract Type DeclaringType {
2480 /// The instance expression associated with this member, if it's a
2481 /// non-static member.
2483 public Expression InstanceExpression;
2485 public static void error176 (Location loc, string name)
2487 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2488 "with an instance reference, qualify it with a type name instead", name);
2491 // TODO: possible optimalization
2492 // Cache resolved constant result in FieldBuilder <-> expression map
2493 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2494 SimpleName original)
2498 // original == null || original.Resolve (...) ==> left
2501 if (left is TypeExpr) {
2503 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2511 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2514 error176 (loc, GetSignatureForError ());
2518 InstanceExpression = left;
2523 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2528 if (InstanceExpression == EmptyExpression.Null) {
2529 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2533 if (InstanceExpression.Type.IsValueType) {
2534 if (InstanceExpression is IMemoryLocation) {
2535 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2537 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2538 InstanceExpression.Emit (ec);
2540 t.AddressOf (ec, AddressOp.Store);
2543 InstanceExpression.Emit (ec);
2545 if (prepare_for_load)
2546 ec.ig.Emit (OpCodes.Dup);
2551 /// MethodGroup Expression.
2553 /// This is a fully resolved expression that evaluates to a type
2555 public class MethodGroupExpr : MemberExpr {
2556 public MethodBase [] Methods;
2557 bool identical_type_name = false;
2560 public MethodGroupExpr (MemberInfo [] mi, Location l)
2562 Methods = new MethodBase [mi.Length];
2563 mi.CopyTo (Methods, 0);
2564 eclass = ExprClass.MethodGroup;
2565 type = TypeManager.object_type;
2569 public MethodGroupExpr (ArrayList list, Location l)
2571 Methods = new MethodBase [list.Count];
2574 list.CopyTo (Methods, 0);
2576 foreach (MemberInfo m in list){
2577 if (!(m is MethodBase)){
2578 Console.WriteLine ("Name " + m.Name);
2579 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2586 eclass = ExprClass.MethodGroup;
2587 type = TypeManager.object_type;
2590 public override Type DeclaringType {
2593 // The methods are arranged in this order:
2594 // derived type -> base type
2596 return Methods [0].DeclaringType;
2600 public bool IdenticalTypeName {
2602 return identical_type_name;
2606 identical_type_name = value;
2610 public bool IsBase {
2619 public override string GetSignatureForError ()
2621 return TypeManager.CSharpSignature (Methods [0]);
2624 public override string Name {
2626 return Methods [0].Name;
2630 public override bool IsInstance {
2632 foreach (MethodBase mb in Methods)
2640 public override bool IsStatic {
2642 foreach (MethodBase mb in Methods)
2650 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2651 SimpleName original)
2653 if (!(left is TypeExpr) &&
2654 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2655 IdenticalTypeName = true;
2657 return base.ResolveMemberAccess (ec, left, loc, original);
2660 override public Expression DoResolve (EmitContext ec)
2663 InstanceExpression = null;
2665 if (InstanceExpression != null) {
2666 InstanceExpression = InstanceExpression.DoResolve (ec);
2667 if (InstanceExpression == null)
2674 public void ReportUsageError ()
2676 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2677 Name + "()' is referenced without parentheses");
2680 override public void Emit (EmitContext ec)
2682 ReportUsageError ();
2685 bool RemoveMethods (bool keep_static)
2687 ArrayList smethods = new ArrayList ();
2689 foreach (MethodBase mb in Methods){
2690 if (mb.IsStatic == keep_static)
2694 if (smethods.Count == 0)
2697 Methods = new MethodBase [smethods.Count];
2698 smethods.CopyTo (Methods, 0);
2704 /// Removes any instance methods from the MethodGroup, returns
2705 /// false if the resulting set is empty.
2707 public bool RemoveInstanceMethods ()
2709 return RemoveMethods (true);
2713 /// Removes any static methods from the MethodGroup, returns
2714 /// false if the resulting set is empty.
2716 public bool RemoveStaticMethods ()
2718 return RemoveMethods (false);
2723 /// Fully resolved expression that evaluates to a Field
2725 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2726 public readonly FieldInfo FieldInfo;
2727 VariableInfo variable_info;
2729 LocalTemporary temp;
2731 bool in_initializer;
2733 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2736 this.in_initializer = in_initializer;
2739 public FieldExpr (FieldInfo fi, Location l)
2742 eclass = ExprClass.Variable;
2743 type = fi.FieldType;
2747 public override string Name {
2749 return FieldInfo.Name;
2753 public override bool IsInstance {
2755 return !FieldInfo.IsStatic;
2759 public override bool IsStatic {
2761 return FieldInfo.IsStatic;
2765 public override Type DeclaringType {
2767 return FieldInfo.DeclaringType;
2771 public override string GetSignatureForError ()
2773 return TypeManager.GetFullNameSignature (FieldInfo);
2776 public VariableInfo VariableInfo {
2778 return variable_info;
2782 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2783 SimpleName original)
2785 Type t = FieldInfo.FieldType;
2787 if (FieldInfo.IsLiteral || (FieldInfo.IsInitOnly && t == TypeManager.decimal_type)) {
2788 IConstant ic = TypeManager.GetConstant (FieldInfo);
2790 if (FieldInfo.IsLiteral) {
2791 ic = new ExternalConstant (FieldInfo);
2793 ic = ExternalConstant.CreateDecimal (FieldInfo);
2795 return base.ResolveMemberAccess (ec, left, loc, original);
2798 TypeManager.RegisterConstant (FieldInfo, ic);
2801 bool left_is_type = left is TypeExpr;
2802 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
2803 Report.SymbolRelatedToPreviousError (FieldInfo);
2804 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
2808 if (ic.ResolveValue ()) {
2809 if (!ec.IsInObsoleteScope)
2810 ic.CheckObsoleteness (loc);
2816 if (t.IsPointer && !ec.InUnsafe) {
2821 return base.ResolveMemberAccess (ec, left, loc, original);
2824 override public Expression DoResolve (EmitContext ec)
2826 return DoResolve (ec, false, false);
2829 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
2831 if (!FieldInfo.IsStatic){
2832 if (InstanceExpression == null){
2834 // This can happen when referencing an instance field using
2835 // a fully qualified type expression: TypeName.InstanceField = xxx
2837 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2841 // Resolve the field's instance expression while flow analysis is turned
2842 // off: when accessing a field "a.b", we must check whether the field
2843 // "a.b" is initialized, not whether the whole struct "a" is initialized.
2845 if (lvalue_instance) {
2846 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
2847 Expression right_side =
2848 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
2849 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
2852 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
2853 InstanceExpression = InstanceExpression.Resolve (ec, rf);
2856 if (InstanceExpression == null)
2859 InstanceExpression.CheckMarshalByRefAccess ();
2862 if (!in_initializer && !ec.IsFieldInitializer) {
2863 ObsoleteAttribute oa;
2864 FieldBase f = TypeManager.GetField (FieldInfo);
2866 if (!ec.IsInObsoleteScope)
2867 f.CheckObsoleteness (loc);
2869 // To be sure that type is external because we do not register generated fields
2870 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
2871 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
2873 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
2877 AnonymousContainer am = ec.CurrentAnonymousMethod;
2879 if (!FieldInfo.IsStatic){
2880 if (!am.IsIterator && (ec.TypeContainer is Struct)){
2881 Report.Error (1673, loc,
2882 "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",
2886 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
2887 ec.CaptureField (this);
2891 // If the instance expression is a local variable or parameter.
2892 IVariable var = InstanceExpression as IVariable;
2893 if ((var == null) || (var.VariableInfo == null))
2896 VariableInfo vi = var.VariableInfo;
2897 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
2900 variable_info = vi.GetSubStruct (FieldInfo.Name);
2904 static readonly int [] codes = {
2905 191, // instance, write access
2906 192, // instance, out access
2907 198, // static, write access
2908 199, // static, out access
2909 1648, // member of value instance, write access
2910 1649, // member of value instance, out access
2911 1650, // member of value static, write access
2912 1651 // member of value static, out access
2915 static readonly string [] msgs = {
2916 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
2917 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2918 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2919 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
2920 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
2921 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2922 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2923 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
2926 // The return value is always null. Returning a value simplifies calling code.
2927 Expression Report_AssignToReadonly (Expression right_side)
2930 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
2934 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
2936 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
2941 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
2943 IVariable var = InstanceExpression as IVariable;
2944 if ((var != null) && (var.VariableInfo != null))
2945 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
2947 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
2948 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
2950 Expression e = DoResolve (ec, lvalue_instance, out_access);
2955 FieldBase fb = TypeManager.GetField (FieldInfo);
2959 if (FieldInfo.IsInitOnly) {
2960 // InitOnly fields can only be assigned in constructors or initializers
2961 if (!ec.IsFieldInitializer && !ec.IsConstructor)
2962 return Report_AssignToReadonly (right_side);
2964 if (ec.IsConstructor) {
2965 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
2966 if (ec.ContainerType != FieldInfo.DeclaringType)
2967 return Report_AssignToReadonly (right_side);
2968 // static InitOnly fields cannot be assigned-to in an instance constructor
2969 if (IsStatic && !ec.IsStatic)
2970 return Report_AssignToReadonly (right_side);
2971 // instance constructors can't modify InitOnly fields of other instances of the same type
2972 if (!IsStatic && !(InstanceExpression is This))
2973 return Report_AssignToReadonly (right_side);
2977 if (right_side == EmptyExpression.OutAccess &&
2978 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
2979 Report.SymbolRelatedToPreviousError (DeclaringType);
2980 Report.Warning (197, 1, loc,
2981 "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",
2982 GetSignatureForError ());
2988 public override void CheckMarshalByRefAccess ()
2990 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
2991 Report.SymbolRelatedToPreviousError (DeclaringType);
2992 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",
2993 GetSignatureForError ());
2997 public bool VerifyFixed ()
2999 IVariable variable = InstanceExpression as IVariable;
3000 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3001 // We defer the InstanceExpression check after the variable check to avoid a
3002 // separate null check on InstanceExpression.
3003 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3006 public override int GetHashCode ()
3008 return FieldInfo.GetHashCode ();
3011 public override bool Equals (object obj)
3013 FieldExpr fe = obj as FieldExpr;
3017 if (FieldInfo != fe.FieldInfo)
3020 if (InstanceExpression == null || fe.InstanceExpression == null)
3023 return InstanceExpression.Equals (fe.InstanceExpression);
3026 public void Emit (EmitContext ec, bool leave_copy)
3028 ILGenerator ig = ec.ig;
3029 bool is_volatile = false;
3031 FieldBase f = TypeManager.GetField (FieldInfo);
3033 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3036 f.SetMemberIsUsed ();
3039 if (FieldInfo.IsStatic){
3041 ig.Emit (OpCodes.Volatile);
3043 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3046 EmitInstance (ec, false);
3049 ig.Emit (OpCodes.Volatile);
3051 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3054 ig.Emit (OpCodes.Ldflda, FieldInfo);
3055 ig.Emit (OpCodes.Ldflda, ff.Element);
3058 ig.Emit (OpCodes.Ldfld, FieldInfo);
3063 ec.ig.Emit (OpCodes.Dup);
3064 if (!FieldInfo.IsStatic) {
3065 temp = new LocalTemporary (this.Type);
3071 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3073 FieldAttributes fa = FieldInfo.Attributes;
3074 bool is_static = (fa & FieldAttributes.Static) != 0;
3075 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3076 ILGenerator ig = ec.ig;
3077 prepared = prepare_for_load;
3079 if (is_readonly && !ec.IsConstructor){
3080 Report_AssignToReadonly (source);
3084 EmitInstance (ec, prepare_for_load);
3088 ec.ig.Emit (OpCodes.Dup);
3089 if (!FieldInfo.IsStatic) {
3090 temp = new LocalTemporary (this.Type);
3095 if (FieldInfo is FieldBuilder){
3096 FieldBase f = TypeManager.GetField (FieldInfo);
3098 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3099 ig.Emit (OpCodes.Volatile);
3106 ig.Emit (OpCodes.Stsfld, FieldInfo);
3108 ig.Emit (OpCodes.Stfld, FieldInfo);
3116 public override void Emit (EmitContext ec)
3121 public void AddressOf (EmitContext ec, AddressOp mode)
3123 ILGenerator ig = ec.ig;
3125 if (FieldInfo is FieldBuilder){
3126 FieldBase f = TypeManager.GetField (FieldInfo);
3128 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3129 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3130 f.GetSignatureForError ());
3134 if ((mode & AddressOp.Store) != 0)
3136 if ((mode & AddressOp.Load) != 0)
3137 f.SetMemberIsUsed ();
3142 // Handle initonly fields specially: make a copy and then
3143 // get the address of the copy.
3146 if (FieldInfo.IsInitOnly){
3148 if (ec.IsConstructor){
3149 if (FieldInfo.IsStatic){
3161 local = ig.DeclareLocal (type);
3162 ig.Emit (OpCodes.Stloc, local);
3163 ig.Emit (OpCodes.Ldloca, local);
3168 if (FieldInfo.IsStatic){
3169 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3171 EmitInstance (ec, false);
3172 ig.Emit (OpCodes.Ldflda, FieldInfo);
3178 // A FieldExpr whose address can not be taken
3180 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3181 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3185 public new void AddressOf (EmitContext ec, AddressOp mode)
3187 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3192 /// Expression that evaluates to a Property. The Assign class
3193 /// might set the `Value' expression if we are in an assignment.
3195 /// This is not an LValue because we need to re-write the expression, we
3196 /// can not take data from the stack and store it.
3198 public class PropertyExpr : MemberExpr, IAssignMethod {
3199 public readonly PropertyInfo PropertyInfo;
3202 // This is set externally by the `BaseAccess' class
3205 MethodInfo getter, setter;
3210 LocalTemporary temp;
3213 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3215 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3218 eclass = ExprClass.PropertyAccess;
3222 type = TypeManager.TypeToCoreType (pi.PropertyType);
3224 ResolveAccessors (containerType);
3227 public override string Name {
3229 return PropertyInfo.Name;
3233 public override bool IsInstance {
3239 public override bool IsStatic {
3245 public override Type DeclaringType {
3247 return PropertyInfo.DeclaringType;
3251 public override string GetSignatureForError ()
3253 return TypeManager.GetFullNameSignature (PropertyInfo);
3256 void FindAccessors (Type invocation_type)
3258 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3259 BindingFlags.Static | BindingFlags.Instance |
3260 BindingFlags.DeclaredOnly;
3262 Type current = PropertyInfo.DeclaringType;
3263 for (; current != null; current = current.BaseType) {
3264 MemberInfo[] group = TypeManager.MemberLookup (
3265 invocation_type, invocation_type, current,
3266 MemberTypes.Property, flags, PropertyInfo.Name, null);
3271 if (group.Length != 1)
3272 // Oooops, can this ever happen ?
3275 PropertyInfo pi = (PropertyInfo) group [0];
3278 getter = pi.GetGetMethod (true);
3281 setter = pi.GetSetMethod (true);
3283 MethodInfo accessor = getter != null ? getter : setter;
3285 if (!accessor.IsVirtual)
3291 // We also perform the permission checking here, as the PropertyInfo does not
3292 // hold the information for the accessibility of its setter/getter
3294 // TODO: can use TypeManager.GetProperty to boost performance
3295 void ResolveAccessors (Type containerType)
3297 FindAccessors (containerType);
3299 if (getter != null) {
3300 IMethodData md = TypeManager.GetMethod (getter);
3302 md.SetMemberIsUsed ();
3304 AccessorTable [getter] = PropertyInfo;
3305 is_static = getter.IsStatic;
3308 if (setter != null) {
3309 IMethodData md = TypeManager.GetMethod (setter);
3311 md.SetMemberIsUsed ();
3313 AccessorTable [setter] = PropertyInfo;
3314 is_static = setter.IsStatic;
3318 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3321 InstanceExpression = null;
3325 if (InstanceExpression == null) {
3326 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3330 if (lvalue_instance)
3331 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3333 InstanceExpression = InstanceExpression.DoResolve (ec);
3334 if (InstanceExpression == null)
3337 InstanceExpression.CheckMarshalByRefAccess ();
3339 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3340 InstanceExpression.Type != ec.ContainerType &&
3341 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3342 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3343 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3350 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3352 // TODO: correctly we should compare arguments but it will lead to bigger changes
3353 if (mi is MethodBuilder) {
3354 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3358 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3360 ParameterData iparams = TypeManager.GetParameterData (mi);
3361 sig.Append (getter ? "get_" : "set_");
3363 sig.Append (iparams.GetSignatureForError ());
3365 Report.SymbolRelatedToPreviousError (mi);
3366 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3367 Name, sig.ToString ());
3370 override public Expression DoResolve (EmitContext ec)
3375 if (getter != null){
3376 if (TypeManager.GetParameterData (getter).Count != 0){
3377 Error_PropertyNotFound (getter, true);
3382 if (getter == null){
3384 // The following condition happens if the PropertyExpr was
3385 // created, but is invalid (ie, the property is inaccessible),
3386 // and we did not want to embed the knowledge about this in
3387 // the caller routine. This only avoids double error reporting.
3392 if (InstanceExpression != EmptyExpression.Null) {
3393 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3394 TypeManager.GetFullNameSignature (PropertyInfo));
3399 bool must_do_cs1540_check = false;
3400 if (getter != null &&
3401 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3402 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3403 if (pm != null && pm.HasCustomAccessModifier) {
3404 Report.SymbolRelatedToPreviousError (pm);
3405 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3406 TypeManager.CSharpSignature (getter));
3409 Report.SymbolRelatedToPreviousError (getter);
3410 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3415 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3419 // Only base will allow this invocation to happen.
3421 if (IsBase && getter.IsAbstract) {
3422 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3426 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3436 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3438 if (right_side == EmptyExpression.OutAccess) {
3439 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3440 GetSignatureForError ());
3444 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3445 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3446 GetSignatureForError ());
3450 if (setter == null){
3452 // The following condition happens if the PropertyExpr was
3453 // created, but is invalid (ie, the property is inaccessible),
3454 // and we did not want to embed the knowledge about this in
3455 // the caller routine. This only avoids double error reporting.
3459 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3460 GetSignatureForError ());
3464 if (TypeManager.GetParameterData (setter).Count != 1){
3465 Error_PropertyNotFound (setter, false);
3469 bool must_do_cs1540_check;
3470 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3471 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3472 if (pm != null && pm.HasCustomAccessModifier) {
3473 Report.SymbolRelatedToPreviousError (pm);
3474 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3475 TypeManager.CSharpSignature (setter));
3478 Report.SymbolRelatedToPreviousError (setter);
3479 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3484 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3488 // Only base will allow this invocation to happen.
3490 if (IsBase && setter.IsAbstract){
3491 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3498 public override void Emit (EmitContext ec)
3503 public void Emit (EmitContext ec, bool leave_copy)
3506 // Special case: length of single dimension array property is turned into ldlen
3508 if ((getter == TypeManager.system_int_array_get_length) ||
3509 (getter == TypeManager.int_array_get_length)){
3510 Type iet = InstanceExpression.Type;
3513 // System.Array.Length can be called, but the Type does not
3514 // support invoking GetArrayRank, so test for that case first
3516 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3518 EmitInstance (ec, false);
3519 ec.ig.Emit (OpCodes.Ldlen);
3520 ec.ig.Emit (OpCodes.Conv_I4);
3525 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3528 ec.ig.Emit (OpCodes.Dup);
3530 temp = new LocalTemporary (this.Type);
3537 // Implements the IAssignMethod interface for assignments
3539 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3541 Expression my_source = source;
3543 prepared = prepare_for_load;
3548 ec.ig.Emit (OpCodes.Dup);
3550 temp = new LocalTemporary (this.Type);
3554 } else if (leave_copy) {
3557 temp = new LocalTemporary (this.Type);
3563 ArrayList args = new ArrayList (1);
3564 args.Add (new Argument (my_source, Argument.AType.Expression));
3566 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3576 /// Fully resolved expression that evaluates to an Event
3578 public class EventExpr : MemberExpr {
3579 public readonly EventInfo EventInfo;
3582 MethodInfo add_accessor, remove_accessor;
3584 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3586 public EventExpr (EventInfo ei, Location loc)
3590 eclass = ExprClass.EventAccess;
3592 add_accessor = TypeManager.GetAddMethod (ei);
3593 remove_accessor = TypeManager.GetRemoveMethod (ei);
3594 if (add_accessor != null)
3595 AccessorTable [add_accessor] = ei;
3596 if (remove_accessor != null)
3597 AccessorTable [remove_accessor] = ei;
3599 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3602 if (EventInfo is MyEventBuilder){
3603 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3604 type = eb.EventType;
3607 type = EventInfo.EventHandlerType;
3610 public override string Name {
3612 return EventInfo.Name;
3616 public override bool IsInstance {
3622 public override bool IsStatic {
3628 public override Type DeclaringType {
3630 return EventInfo.DeclaringType;
3634 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3635 SimpleName original)
3638 // If the event is local to this class, we transform ourselves into a FieldExpr
3641 if (EventInfo.DeclaringType == ec.ContainerType ||
3642 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3643 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3646 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3649 Report.Error (-200, loc, "Internal error!!");
3653 InstanceExpression = null;
3655 return ml.ResolveMemberAccess (ec, left, loc, original);
3659 return base.ResolveMemberAccess (ec, left, loc, original);
3663 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3666 InstanceExpression = null;
3670 if (InstanceExpression == null) {
3671 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3675 InstanceExpression = InstanceExpression.DoResolve (ec);
3676 if (InstanceExpression == null)
3680 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3681 // However, in the Event case, we reported a CS0122 instead.
3683 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3684 InstanceExpression.Type != ec.ContainerType &&
3685 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3686 Report.SymbolRelatedToPreviousError (EventInfo);
3687 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3694 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3696 return DoResolve (ec);
3699 public override Expression DoResolve (EmitContext ec)
3701 bool must_do_cs1540_check;
3702 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3703 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3704 Report.SymbolRelatedToPreviousError (EventInfo);
3705 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3709 if (!InstanceResolve (ec, must_do_cs1540_check))
3715 public override void Emit (EmitContext ec)
3717 if (InstanceExpression is This)
3718 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3720 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3721 "(except on the defining type)", Name);
3724 public override string GetSignatureForError ()
3726 return TypeManager.CSharpSignature (EventInfo);
3729 public void EmitAddOrRemove (EmitContext ec, Expression source)
3731 BinaryDelegate source_del = (BinaryDelegate) source;
3732 Expression handler = source_del.Right;
3734 Argument arg = new Argument (handler, Argument.AType.Expression);
3735 ArrayList args = new ArrayList ();
3739 if (source_del.IsAddition)
3740 Invocation.EmitCall (
3741 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3743 Invocation.EmitCall (
3744 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3749 public class TemporaryVariable : Expression, IMemoryLocation
3753 public TemporaryVariable (Type type, Location loc)
3757 eclass = ExprClass.Value;
3760 public override Expression DoResolve (EmitContext ec)
3765 TypeExpr te = new TypeExpression (type, loc);
3766 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
3767 if (!li.Resolve (ec))
3770 AnonymousContainer am = ec.CurrentAnonymousMethod;
3771 if ((am != null) && am.IsIterator)
3772 ec.CaptureVariable (li);
3777 public override void Emit (EmitContext ec)
3779 ILGenerator ig = ec.ig;
3781 if (li.FieldBuilder != null) {
3782 ig.Emit (OpCodes.Ldarg_0);
3783 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
3785 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
3789 public void EmitLoadAddress (EmitContext ec)
3791 ILGenerator ig = ec.ig;
3793 if (li.FieldBuilder != null) {
3794 ig.Emit (OpCodes.Ldarg_0);
3795 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
3797 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
3801 public void Store (EmitContext ec, Expression right_side)
3803 if (li.FieldBuilder != null)
3804 ec.ig.Emit (OpCodes.Ldarg_0);
3806 right_side.Emit (ec);
3807 if (li.FieldBuilder != null) {
3808 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
3810 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
3814 public void EmitThis (EmitContext ec)
3816 if (li.FieldBuilder != null) {
3817 ec.ig.Emit (OpCodes.Ldarg_0);
3821 public void EmitStore (ILGenerator ig)
3823 if (li.FieldBuilder != null)
3824 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
3826 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
3829 public void AddressOf (EmitContext ec, AddressOp mode)
3831 EmitLoadAddress (ec);