2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess ()
140 public virtual bool GetAttributableValue (Type valueType, out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
169 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
189 /// Performs semantic analysis on the Expression
193 /// The Resolve method is invoked to perform the semantic analysis
196 /// The return value is an expression (it can be the
197 /// same expression in some cases) or a new
198 /// expression that better represents this node.
200 /// For example, optimizations of Unary (LiteralInt)
201 /// would return a new LiteralInt with a negated
204 /// If there is an error during semantic analysis,
205 /// then an error should be reported (using Report)
206 /// and a null value should be returned.
208 /// There are two side effects expected from calling
209 /// Resolve(): the the field variable "eclass" should
210 /// be set to any value of the enumeration
211 /// `ExprClass' and the type variable should be set
212 /// to a valid type (this is the type of the
215 public abstract Expression DoResolve (EmitContext ec);
217 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
223 // This is used if the expression should be resolved as a type or namespace name.
224 // the default implementation fails.
226 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
232 // This is used to resolve the expression as a type, a null
233 // value will be returned if the expression is not a type
236 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
238 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
242 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
243 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
244 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
247 // Constrains don't need to be checked for overrides
248 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
249 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
254 ConstructedType ct = te as ConstructedType;
255 if ((ct != null) && !ct.CheckConstraints (ec))
261 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
263 int errors = Report.Errors;
265 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
268 if (!silent && errors == Report.Errors)
269 Report.Error (118, loc, "Expecting a type.");
273 if (fne.eclass != ExprClass.Type) {
274 if (!silent && errors == Report.Errors)
275 fne.Error_UnexpectedKind (null, "type", loc);
279 TypeExpr te = fne as TypeExpr;
281 if (!te.CheckAccessLevel (ec.DeclContainer)) {
282 Report.SymbolRelatedToPreviousError (te.Type);
283 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
291 public static void ErrorIsInaccesible (Location loc, string name)
293 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
296 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
298 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
299 + " the qualifier must be of type `{2}' (or derived from it)",
300 TypeManager.GetFullNameSignature (m),
301 TypeManager.CSharpName (qualifier),
302 TypeManager.CSharpName (container));
306 protected void Error_CannotAssign (string to, string roContext)
308 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
312 public static void Error_VoidInvalidInTheContext (Location loc)
314 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
317 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
319 if (Type.FullName == target.FullName){
320 Report.ExtraInformation (loc,
322 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
323 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
328 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
329 GetSignatureForError (), TypeManager.CSharpName (target));
333 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
334 bool b = Convert.ExplicitNumericConversion (e, target) != null;
336 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
337 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
338 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
342 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
343 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
344 GetSignatureForError (), TypeManager.CSharpName (target));
348 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
349 Type == TypeManager.anonymous_method_type ?
350 "anonymous method" : "`" + GetSignatureForError () + "'",
351 TypeManager.CSharpName (target));
354 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
356 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 TypeManager.CSharpName (type), name);
360 ResolveFlags ExprClassToResolveFlags
365 case ExprClass.Namespace:
366 return ResolveFlags.Type;
368 case ExprClass.MethodGroup:
369 return ResolveFlags.MethodGroup;
371 case ExprClass.Value:
372 case ExprClass.Variable:
373 case ExprClass.PropertyAccess:
374 case ExprClass.EventAccess:
375 case ExprClass.IndexerAccess:
376 return ResolveFlags.VariableOrValue;
379 throw new Exception ("Expression " + GetType () +
380 " ExprClass is Invalid after resolve");
386 /// Resolves an expression and performs semantic analysis on it.
390 /// Currently Resolve wraps DoResolve to perform sanity
391 /// checking and assertion checking on what we expect from Resolve.
393 public Expression Resolve (EmitContext ec, ResolveFlags flags)
395 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
396 return ResolveAsTypeStep (ec, false);
398 bool do_flow_analysis = ec.DoFlowAnalysis;
399 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
400 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
401 do_flow_analysis = false;
402 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
403 omit_struct_analysis = true;
406 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
407 if (this is SimpleName) {
408 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
409 e = ((SimpleName) this).DoResolve (ec, intermediate);
418 if ((flags & e.ExprClassToResolveFlags) == 0) {
419 e.Error_UnexpectedKind (flags, loc);
423 if (e.type == null && !(e is Namespace)) {
424 throw new Exception (
425 "Expression " + e.GetType () +
426 " did not set its type after Resolve\n" +
427 "called from: " + this.GetType ());
434 /// Resolves an expression and performs semantic analysis on it.
436 public Expression Resolve (EmitContext ec)
438 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
440 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
441 ((MethodGroupExpr) e).ReportUsageError ();
447 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
449 Expression e = Resolve (ec);
453 Constant c = e as Constant;
457 Type constant_type = null;
458 if (mc is MemberBase) {
459 constant_type = ((MemberBase)mc).MemberType;
462 Const.Error_ExpressionMustBeConstant (constant_type, loc, mc.GetSignatureForError ());
467 /// Resolves an expression for LValue assignment
471 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
472 /// checking and assertion checking on what we expect from Resolve
474 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
476 int errors = Report.Errors;
477 bool out_access = right_side == EmptyExpression.OutAccess;
479 Expression e = DoResolveLValue (ec, right_side);
481 if (e != null && out_access && !(e is IMemoryLocation)) {
482 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
483 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
485 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
486 // e.GetType () + " " + e.GetSignatureForError ());
491 if (errors == Report.Errors) {
493 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
495 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
500 if (e.eclass == ExprClass.Invalid)
501 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
503 if (e.eclass == ExprClass.MethodGroup) {
504 ((MethodGroupExpr) e).ReportUsageError ();
508 if ((e.type == null) && !(e is ConstructedType))
509 throw new Exception ("Expression " + e + " did not set its type after Resolve");
515 /// Emits the code for the expression
519 /// The Emit method is invoked to generate the code
520 /// for the expression.
522 public abstract void Emit (EmitContext ec);
524 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
527 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
531 /// Protected constructor. Only derivate types should
532 /// be able to be created
535 protected Expression ()
537 eclass = ExprClass.Invalid;
542 /// Returns a literalized version of a literal FieldInfo
546 /// The possible return values are:
547 /// IntConstant, UIntConstant
548 /// LongLiteral, ULongConstant
549 /// FloatConstant, DoubleConstant
552 /// The value returned is already resolved.
554 public static Constant Constantify (object v, Type t)
556 if (t == TypeManager.int32_type)
557 return new IntConstant ((int) v, Location.Null);
558 else if (t == TypeManager.uint32_type)
559 return new UIntConstant ((uint) v, Location.Null);
560 else if (t == TypeManager.int64_type)
561 return new LongConstant ((long) v, Location.Null);
562 else if (t == TypeManager.uint64_type)
563 return new ULongConstant ((ulong) v, Location.Null);
564 else if (t == TypeManager.float_type)
565 return new FloatConstant ((float) v, Location.Null);
566 else if (t == TypeManager.double_type)
567 return new DoubleConstant ((double) v, Location.Null);
568 else if (t == TypeManager.string_type)
569 return new StringConstant ((string) v, Location.Null);
570 else if (t == TypeManager.short_type)
571 return new ShortConstant ((short)v, Location.Null);
572 else if (t == TypeManager.ushort_type)
573 return new UShortConstant ((ushort)v, Location.Null);
574 else if (t == TypeManager.sbyte_type)
575 return new SByteConstant ((sbyte)v, Location.Null);
576 else if (t == TypeManager.byte_type)
577 return new ByteConstant ((byte)v, Location.Null);
578 else if (t == TypeManager.char_type)
579 return new CharConstant ((char)v, Location.Null);
580 else if (t == TypeManager.bool_type)
581 return new BoolConstant ((bool) v, Location.Null);
582 else if (t == TypeManager.decimal_type)
583 return new DecimalConstant ((decimal) v, Location.Null);
584 else if (TypeManager.IsEnumType (t)){
585 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
587 real_type = System.Enum.GetUnderlyingType (real_type);
589 Constant e = Constantify (v, real_type);
591 return new EnumConstant (e, t);
592 } else if (v == null && !TypeManager.IsValueType (t))
593 return new NullLiteral (Location.Null);
595 throw new Exception ("Unknown type for constant (" + t +
600 /// Returns a fully formed expression after a MemberLookup
603 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
606 return new EventExpr ((EventInfo) mi, loc);
607 else if (mi is FieldInfo)
608 return new FieldExpr ((FieldInfo) mi, loc);
609 else if (mi is PropertyInfo)
610 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
611 else if (mi is Type){
612 return new TypeExpression ((System.Type) mi, loc);
618 protected static ArrayList almostMatchedMembers = new ArrayList (4);
621 // FIXME: Probably implement a cache for (t,name,current_access_set)?
623 // This code could use some optimizations, but we need to do some
624 // measurements. For example, we could use a delegate to `flag' when
625 // something can not any longer be a method-group (because it is something
629 // If the return value is an Array, then it is an array of
632 // If the return value is an MemberInfo, it is anything, but a Method
636 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
637 // the arguments here and have MemberLookup return only the methods that
638 // match the argument count/type, unlike we are doing now (we delay this
641 // This is so we can catch correctly attempts to invoke instance methods
642 // from a static body (scan for error 120 in ResolveSimpleName).
645 // FIXME: Potential optimization, have a static ArrayList
648 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
649 MemberTypes mt, BindingFlags bf, Location loc)
651 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
655 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
656 // `qualifier_type' or null to lookup members in the current class.
659 public static Expression MemberLookup (Type container_type,
660 Type qualifier_type, Type queried_type,
661 string name, MemberTypes mt,
662 BindingFlags bf, Location loc)
664 almostMatchedMembers.Clear ();
666 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
667 queried_type, mt, bf, name, almostMatchedMembers);
673 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
674 MemberInfo non_method = null;
675 ArrayList methods = new ArrayList (2);
677 foreach (MemberInfo m in mi) {
678 if (m is MethodBase) {
683 if (non_method == null) {
691 Report.SymbolRelatedToPreviousError (m);
692 Report.SymbolRelatedToPreviousError (non_method);
693 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
694 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
698 if (non_method != null && is_interface) {
699 MethodBase method = (MethodBase)methods[0];
700 Report.SymbolRelatedToPreviousError (method);
701 Report.SymbolRelatedToPreviousError (non_method);
702 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
703 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
706 if (methods.Count == 0)
707 return new MethodGroupExpr (mi, loc);
709 return new MethodGroupExpr (methods, loc);
712 if (mi [0] is MethodBase)
713 return new MethodGroupExpr (mi, loc);
715 return ExprClassFromMemberInfo (container_type, mi [0], loc);
718 public const MemberTypes AllMemberTypes =
719 MemberTypes.Constructor |
723 MemberTypes.NestedType |
724 MemberTypes.Property;
726 public const BindingFlags AllBindingFlags =
727 BindingFlags.Public |
728 BindingFlags.Static |
729 BindingFlags.Instance;
731 public static Expression MemberLookup (Type container_type, Type queried_type,
732 string name, Location loc)
734 return MemberLookup (container_type, null, queried_type, name,
735 AllMemberTypes, AllBindingFlags, loc);
738 public static Expression MemberLookup (Type container_type, Type qualifier_type,
739 Type queried_type, string name, Location loc)
741 return MemberLookup (container_type, qualifier_type, queried_type,
742 name, AllMemberTypes, AllBindingFlags, loc);
745 public static Expression MethodLookup (EmitContext ec, Type queried_type,
746 string name, Location loc)
748 return MemberLookup (ec.ContainerType, null, queried_type, name,
749 MemberTypes.Method, AllBindingFlags, loc);
753 /// This is a wrapper for MemberLookup that is not used to "probe", but
754 /// to find a final definition. If the final definition is not found, we
755 /// look for private members and display a useful debugging message if we
758 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
759 Type queried_type, string name, Location loc)
761 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
762 AllMemberTypes, AllBindingFlags, loc);
765 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
766 Type queried_type, string name,
767 MemberTypes mt, BindingFlags bf,
772 int errors = Report.Errors;
774 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
776 if (e == null && errors == Report.Errors)
777 // No errors were reported by MemberLookup, but there was an error.
778 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
783 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
784 Type queried_type, string name,
785 string class_name, bool complain_if_none_found,
788 if (almostMatchedMembers.Count != 0) {
789 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
790 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
791 for (int j = 0; j < i; ++j) {
792 if (m == almostMatchedMembers [j]) {
800 Type declaring_type = m.DeclaringType;
802 Report.SymbolRelatedToPreviousError (m);
803 if (qualifier_type == null) {
804 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
805 TypeManager.CSharpName (m.DeclaringType),
806 TypeManager.CSharpName (container_type));
808 } else if (qualifier_type != container_type &&
809 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
810 // Although a derived class can access protected members of
811 // its base class it cannot do so through an instance of the
812 // base class (CS1540). If the qualifier_type is a base of the
813 // ec.ContainerType and the lookup succeeds with the latter one,
814 // then we are in this situation.
815 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
817 Report.SymbolRelatedToPreviousError (m);
818 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
821 almostMatchedMembers.Clear ();
825 MemberInfo[] lookup = null;
826 if (queried_type == null) {
827 class_name = "global::";
829 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
830 AllMemberTypes, AllBindingFlags |
831 BindingFlags.NonPublic, name, null);
834 if (lookup == null) {
835 if (!complain_if_none_found)
838 if (class_name != null)
839 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
842 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
846 if (TypeManager.MemberLookup (queried_type, null, queried_type,
847 AllMemberTypes, AllBindingFlags |
848 BindingFlags.NonPublic, name, null) == null) {
849 if ((lookup.Length == 1) && (lookup [0] is Type)) {
850 Type t = (Type) lookup [0];
852 Report.Error (305, loc,
853 "Using the generic type `{0}' " +
854 "requires {1} type arguments",
855 TypeManager.CSharpName (t),
856 TypeManager.GetNumberOfTypeArguments (t).ToString ());
861 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
862 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
863 if (name == ".ctor" && ml.Count == 0)
865 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
869 Report.SymbolRelatedToPreviousError (lookup [0]);
870 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
874 /// Returns an expression that can be used to invoke operator true
875 /// on the expression if it exists.
877 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
879 return GetOperatorTrueOrFalse (ec, e, true, loc);
883 /// Returns an expression that can be used to invoke operator false
884 /// on the expression if it exists.
886 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
888 return GetOperatorTrueOrFalse (ec, e, false, loc);
891 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
894 Expression operator_group;
896 if (TypeManager.IsNullableType (e.Type))
897 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
899 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
900 if (operator_group == null)
903 ArrayList arguments = new ArrayList ();
904 arguments.Add (new Argument (e, Argument.AType.Expression));
905 method = Invocation.OverloadResolve (
906 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
911 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
915 /// Resolves the expression `e' into a boolean expression: either through
916 /// an implicit conversion, or through an `operator true' invocation
918 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
924 if (e.Type == TypeManager.bool_type)
927 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
929 if (converted != null)
933 // If no implicit conversion to bool exists, try using `operator true'
935 converted = Expression.GetOperatorTrue (ec, e, loc);
936 if (converted == null){
937 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
943 public virtual string ExprClassName
947 case ExprClass.Invalid:
949 case ExprClass.Value:
951 case ExprClass.Variable:
953 case ExprClass.Namespace:
957 case ExprClass.MethodGroup:
958 return "method group";
959 case ExprClass.PropertyAccess:
960 return "property access";
961 case ExprClass.EventAccess:
962 return "event access";
963 case ExprClass.IndexerAccess:
964 return "indexer access";
965 case ExprClass.Nothing:
968 throw new Exception ("Should not happen");
973 /// Reports that we were expecting `expr' to be of class `expected'
975 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
977 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
980 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
982 string name = GetSignatureForError ();
984 name = ds.GetSignatureForError () + '.' + name;
986 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
987 name, was, expected);
990 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
992 string [] valid = new string [4];
995 if ((flags & ResolveFlags.VariableOrValue) != 0) {
996 valid [count++] = "variable";
997 valid [count++] = "value";
1000 if ((flags & ResolveFlags.Type) != 0)
1001 valid [count++] = "type";
1003 if ((flags & ResolveFlags.MethodGroup) != 0)
1004 valid [count++] = "method group";
1007 valid [count++] = "unknown";
1009 StringBuilder sb = new StringBuilder (valid [0]);
1010 for (int i = 1; i < count - 1; i++) {
1012 sb.Append (valid [i]);
1015 sb.Append ("' or `");
1016 sb.Append (valid [count - 1]);
1019 Report.Error (119, loc,
1020 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1023 public static void UnsafeError (Location loc)
1025 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1029 // Load the object from the pointer.
1031 public static void LoadFromPtr (ILGenerator ig, Type t)
1033 if (t == TypeManager.int32_type)
1034 ig.Emit (OpCodes.Ldind_I4);
1035 else if (t == TypeManager.uint32_type)
1036 ig.Emit (OpCodes.Ldind_U4);
1037 else if (t == TypeManager.short_type)
1038 ig.Emit (OpCodes.Ldind_I2);
1039 else if (t == TypeManager.ushort_type)
1040 ig.Emit (OpCodes.Ldind_U2);
1041 else if (t == TypeManager.char_type)
1042 ig.Emit (OpCodes.Ldind_U2);
1043 else if (t == TypeManager.byte_type)
1044 ig.Emit (OpCodes.Ldind_U1);
1045 else if (t == TypeManager.sbyte_type)
1046 ig.Emit (OpCodes.Ldind_I1);
1047 else if (t == TypeManager.uint64_type)
1048 ig.Emit (OpCodes.Ldind_I8);
1049 else if (t == TypeManager.int64_type)
1050 ig.Emit (OpCodes.Ldind_I8);
1051 else if (t == TypeManager.float_type)
1052 ig.Emit (OpCodes.Ldind_R4);
1053 else if (t == TypeManager.double_type)
1054 ig.Emit (OpCodes.Ldind_R8);
1055 else if (t == TypeManager.bool_type)
1056 ig.Emit (OpCodes.Ldind_I1);
1057 else if (t == TypeManager.intptr_type)
1058 ig.Emit (OpCodes.Ldind_I);
1059 else if (TypeManager.IsEnumType (t)) {
1060 if (t == TypeManager.enum_type)
1061 ig.Emit (OpCodes.Ldind_Ref);
1063 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1064 } else if (t.IsValueType || t.IsGenericParameter)
1065 ig.Emit (OpCodes.Ldobj, t);
1066 else if (t.IsPointer)
1067 ig.Emit (OpCodes.Ldind_I);
1069 ig.Emit (OpCodes.Ldind_Ref);
1073 // The stack contains the pointer and the value of type `type'
1075 public static void StoreFromPtr (ILGenerator ig, Type type)
1077 if (TypeManager.IsEnumType (type))
1078 type = TypeManager.EnumToUnderlying (type);
1079 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1080 ig.Emit (OpCodes.Stind_I4);
1081 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1082 ig.Emit (OpCodes.Stind_I8);
1083 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1084 type == TypeManager.ushort_type)
1085 ig.Emit (OpCodes.Stind_I2);
1086 else if (type == TypeManager.float_type)
1087 ig.Emit (OpCodes.Stind_R4);
1088 else if (type == TypeManager.double_type)
1089 ig.Emit (OpCodes.Stind_R8);
1090 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1091 type == TypeManager.bool_type)
1092 ig.Emit (OpCodes.Stind_I1);
1093 else if (type == TypeManager.intptr_type)
1094 ig.Emit (OpCodes.Stind_I);
1095 else if (type.IsValueType || type.IsGenericParameter)
1096 ig.Emit (OpCodes.Stobj, type);
1098 ig.Emit (OpCodes.Stind_Ref);
1102 // Returns the size of type `t' if known, otherwise, 0
1104 public static int GetTypeSize (Type t)
1106 t = TypeManager.TypeToCoreType (t);
1107 if (t == TypeManager.int32_type ||
1108 t == TypeManager.uint32_type ||
1109 t == TypeManager.float_type)
1111 else if (t == TypeManager.int64_type ||
1112 t == TypeManager.uint64_type ||
1113 t == TypeManager.double_type)
1115 else if (t == TypeManager.byte_type ||
1116 t == TypeManager.sbyte_type ||
1117 t == TypeManager.bool_type)
1119 else if (t == TypeManager.short_type ||
1120 t == TypeManager.char_type ||
1121 t == TypeManager.ushort_type)
1123 else if (t == TypeManager.decimal_type)
1129 public static void Error_NegativeArrayIndex (Location loc)
1131 Report.Error (248, loc, "Cannot create an array with a negative size");
1134 protected void Error_CannotCallAbstractBase (string name)
1136 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1140 // Converts `source' to an int, uint, long or ulong.
1142 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1146 using (ec.With (EmitContext.Flags.CheckState, true)) {
1147 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1149 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1151 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1153 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1155 if (target == null) {
1156 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1162 // Only positive constants are allowed at compile time
1164 if (target is Constant){
1165 if (target is IntConstant){
1166 if (((IntConstant) target).Value < 0){
1167 Error_NegativeArrayIndex (loc);
1172 if (target is LongConstant){
1173 if (((LongConstant) target).Value < 0){
1174 Error_NegativeArrayIndex (loc);
1187 /// This is just a base class for expressions that can
1188 /// appear on statements (invocations, object creation,
1189 /// assignments, post/pre increment and decrement). The idea
1190 /// being that they would support an extra Emition interface that
1191 /// does not leave a result on the stack.
1193 public abstract class ExpressionStatement : Expression {
1195 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1197 Expression e = Resolve (ec);
1201 ExpressionStatement es = e as ExpressionStatement;
1203 Error (201, "Only assignment, call, increment, decrement and new object " +
1204 "expressions can be used as a statement");
1210 /// Requests the expression to be emitted in a `statement'
1211 /// context. This means that no new value is left on the
1212 /// stack after invoking this method (constrasted with
1213 /// Emit that will always leave a value on the stack).
1215 public abstract void EmitStatement (EmitContext ec);
1219 /// This kind of cast is used to encapsulate the child
1220 /// whose type is child.Type into an expression that is
1221 /// reported to return "return_type". This is used to encapsulate
1222 /// expressions which have compatible types, but need to be dealt
1223 /// at higher levels with.
1225 /// For example, a "byte" expression could be encapsulated in one
1226 /// of these as an "unsigned int". The type for the expression
1227 /// would be "unsigned int".
1230 public class EmptyCast : Expression {
1231 protected readonly Expression child;
1233 public EmptyCast (Expression child, Type return_type)
1235 eclass = child.eclass;
1236 loc = child.Location;
1241 public override Expression DoResolve (EmitContext ec)
1243 // This should never be invoked, we are born in fully
1244 // initialized state.
1249 public override void Emit (EmitContext ec)
1254 public override bool GetAttributableValue (Type valueType, out object value)
1256 return child.GetAttributableValue (valueType, out value);
1261 /// This is a numeric cast to a Decimal
1263 public class CastToDecimal : EmptyCast {
1265 MethodInfo conversion_operator;
1267 public CastToDecimal (Expression child)
1268 : this (child, false)
1272 public CastToDecimal (Expression child, bool find_explicit)
1273 : base (child, TypeManager.decimal_type)
1275 conversion_operator = GetConversionOperator (find_explicit);
1277 if (conversion_operator == null)
1278 throw new InternalErrorException ("Outer conversion routine is out of sync");
1281 // Returns the implicit operator that converts from
1282 // 'child.Type' to System.Decimal.
1283 MethodInfo GetConversionOperator (bool find_explicit)
1285 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1287 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1288 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1290 foreach (MethodInfo oper in mi) {
1291 ParameterData pd = TypeManager.GetParameterData (oper);
1293 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1299 public override void Emit (EmitContext ec)
1301 ILGenerator ig = ec.ig;
1304 ig.Emit (OpCodes.Call, conversion_operator);
1309 /// This is an explicit numeric cast from a Decimal
1311 public class CastFromDecimal : EmptyCast
1313 static IDictionary operators;
1315 public CastFromDecimal (Expression child, Type return_type)
1316 : base (child, return_type)
1318 if (child.Type != TypeManager.decimal_type)
1319 throw new InternalErrorException (
1320 "The expected type is Decimal, instead it is " + child.Type.FullName);
1323 // Returns the explicit operator that converts from an
1324 // express of type System.Decimal to 'type'.
1325 public Expression Resolve ()
1327 if (operators == null) {
1328 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1329 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1330 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1332 operators = new System.Collections.Specialized.HybridDictionary ();
1333 foreach (MethodInfo oper in all_oper) {
1334 ParameterData pd = TypeManager.GetParameterData (oper);
1335 if (pd.ParameterType (0) == TypeManager.decimal_type)
1336 operators.Add (oper.ReturnType, oper);
1340 return operators.Contains (type) ? this : null;
1343 public override void Emit (EmitContext ec)
1345 ILGenerator ig = ec.ig;
1348 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1353 // We need to special case this since an empty cast of
1354 // a NullLiteral is still a Constant
1356 public class NullCast : Constant {
1357 public Constant child;
1359 public NullCast (Constant child, Type return_type):
1360 base (Location.Null)
1362 eclass = child.eclass;
1367 override public string AsString ()
1372 public override object GetValue ()
1377 public override Expression DoResolve (EmitContext ec)
1379 // This should never be invoked, we are born in fully
1380 // initialized state.
1385 public override void Emit (EmitContext ec)
1390 public override Constant Increment ()
1392 throw new NotSupportedException ();
1395 public override bool IsDefaultValue {
1401 public override bool IsNegative {
1407 public override Constant Reduce (bool inCheckedContext, Type target_type)
1409 if (type == target_type)
1410 return child.Reduce (inCheckedContext, target_type);
1419 /// This class is used to wrap literals which belong inside Enums
1421 public class EnumConstant : Constant {
1422 public Constant Child;
1424 public EnumConstant (Constant child, Type enum_type):
1425 base (child.Location)
1427 eclass = child.eclass;
1432 public override Expression DoResolve (EmitContext ec)
1434 // This should never be invoked, we are born in fully
1435 // initialized state.
1440 public override void Emit (EmitContext ec)
1445 public override bool GetAttributableValue (Type valueType, out object value)
1447 value = GetTypedValue ();
1451 public override string GetSignatureForError()
1453 return TypeManager.CSharpName (Type);
1456 public override object GetValue ()
1458 return Child.GetValue ();
1461 public override object GetTypedValue ()
1463 // FIXME: runtime is not ready to work with just emited enums
1464 if (!RootContext.StdLib) {
1465 return Child.GetValue ();
1468 return System.Enum.ToObject (type, Child.GetValue ());
1471 public override string AsString ()
1473 return Child.AsString ();
1476 public override DoubleConstant ConvertToDouble ()
1478 return Child.ConvertToDouble ();
1481 public override FloatConstant ConvertToFloat ()
1483 return Child.ConvertToFloat ();
1486 public override ULongConstant ConvertToULong ()
1488 return Child.ConvertToULong ();
1491 public override LongConstant ConvertToLong ()
1493 return Child.ConvertToLong ();
1496 public override UIntConstant ConvertToUInt ()
1498 return Child.ConvertToUInt ();
1501 public override IntConstant ConvertToInt ()
1503 return Child.ConvertToInt ();
1506 public override Constant Increment()
1508 return new EnumConstant (Child.Increment (), type);
1511 public override bool IsDefaultValue {
1513 return Child.IsDefaultValue;
1517 public override bool IsZeroInteger {
1518 get { return Child.IsZeroInteger; }
1521 public override bool IsNegative {
1523 return Child.IsNegative;
1527 public override Constant Reduce(bool inCheckedContext, Type target_type)
1529 if (Child.Type == target_type)
1532 return Child.Reduce (inCheckedContext, target_type);
1535 public override Constant ToType (Type type, Location loc)
1538 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1539 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1542 if (type.UnderlyingSystemType != Child.Type)
1543 Child = Child.ToType (type.UnderlyingSystemType, loc);
1547 if (!Convert.ImplicitStandardConversionExists (this, type)){
1548 Error_ValueCannotBeConverted (loc, type, false);
1552 return Child.ToType (type, loc);
1558 /// This kind of cast is used to encapsulate Value Types in objects.
1560 /// The effect of it is to box the value type emitted by the previous
1563 public class BoxedCast : EmptyCast {
1565 public BoxedCast (Expression expr, Type target_type)
1566 : base (expr, target_type)
1568 eclass = ExprClass.Value;
1571 public override Expression DoResolve (EmitContext ec)
1573 // This should never be invoked, we are born in fully
1574 // initialized state.
1579 public override void Emit (EmitContext ec)
1583 ec.ig.Emit (OpCodes.Box, child.Type);
1587 public class UnboxCast : EmptyCast {
1588 public UnboxCast (Expression expr, Type return_type)
1589 : base (expr, return_type)
1593 public override Expression DoResolve (EmitContext ec)
1595 // This should never be invoked, we are born in fully
1596 // initialized state.
1601 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1603 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1604 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1605 return base.DoResolveLValue (ec, right_side);
1608 public override void Emit (EmitContext ec)
1611 ILGenerator ig = ec.ig;
1614 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1615 ig.Emit (OpCodes.Unbox_Any, t);
1617 ig.Emit (OpCodes.Unbox, t);
1619 LoadFromPtr (ig, t);
1625 /// This is used to perform explicit numeric conversions.
1627 /// Explicit numeric conversions might trigger exceptions in a checked
1628 /// context, so they should generate the conv.ovf opcodes instead of
1631 public class ConvCast : EmptyCast {
1632 public enum Mode : byte {
1633 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1635 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1636 U2_I1, U2_U1, U2_I2, U2_CH,
1637 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1638 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1639 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1640 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1641 CH_I1, CH_U1, CH_I2,
1642 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1643 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1648 public ConvCast (Expression child, Type return_type, Mode m)
1649 : base (child, return_type)
1654 public override Expression DoResolve (EmitContext ec)
1656 // This should never be invoked, we are born in fully
1657 // initialized state.
1662 public override string ToString ()
1664 return String.Format ("ConvCast ({0}, {1})", mode, child);
1667 public override void Emit (EmitContext ec)
1669 ILGenerator ig = ec.ig;
1675 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1676 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1677 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1678 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1679 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1681 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1682 case Mode.U1_CH: /* nothing */ break;
1684 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1685 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1686 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1687 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1688 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1689 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1691 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1692 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1693 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1694 case Mode.U2_CH: /* nothing */ break;
1696 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1697 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1698 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1699 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1700 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1701 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1702 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1704 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1705 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1706 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1707 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1708 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1709 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1711 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1712 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1713 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1714 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1715 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1716 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1717 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1718 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1720 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1721 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1722 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1723 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1724 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1725 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1726 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1727 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1729 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1730 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1731 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1733 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1734 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1735 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1736 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1737 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1738 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1739 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1740 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1741 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1743 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1744 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1745 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1746 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1747 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1748 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1749 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1750 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1751 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1752 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1756 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1757 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1758 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1759 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1760 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1762 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1763 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1765 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1766 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1767 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1768 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1769 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1770 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1772 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1773 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1774 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1775 case Mode.U2_CH: /* nothing */ break;
1777 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1778 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1779 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1780 case Mode.I4_U4: /* nothing */ break;
1781 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1782 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1783 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1785 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1786 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1787 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1788 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1789 case Mode.U4_I4: /* nothing */ break;
1790 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1792 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1793 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1794 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1795 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1796 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1797 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1798 case Mode.I8_U8: /* nothing */ break;
1799 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1801 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1802 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1803 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1804 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1805 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1806 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1807 case Mode.U8_I8: /* nothing */ break;
1808 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1810 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1811 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1812 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1814 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1815 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1816 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1817 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1818 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1819 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1820 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1821 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1822 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1824 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1825 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1826 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1827 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1828 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1829 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1830 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1831 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1832 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1833 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1839 public class OpcodeCast : EmptyCast {
1843 public OpcodeCast (Expression child, Type return_type, OpCode op)
1844 : base (child, return_type)
1848 second_valid = false;
1851 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1852 : base (child, return_type)
1857 second_valid = true;
1860 public override Expression DoResolve (EmitContext ec)
1862 // This should never be invoked, we are born in fully
1863 // initialized state.
1868 public override void Emit (EmitContext ec)
1879 /// This kind of cast is used to encapsulate a child and cast it
1880 /// to the class requested
1882 public class ClassCast : EmptyCast {
1883 public ClassCast (Expression child, Type return_type)
1884 : base (child, return_type)
1889 public override Expression DoResolve (EmitContext ec)
1891 // This should never be invoked, we are born in fully
1892 // initialized state.
1897 public override void Emit (EmitContext ec)
1901 if (child.Type.IsGenericParameter)
1902 ec.ig.Emit (OpCodes.Box, child.Type);
1904 if (type.IsGenericParameter)
1905 ec.ig.Emit (OpCodes.Unbox_Any, type);
1907 ec.ig.Emit (OpCodes.Castclass, type);
1912 /// SimpleName expressions are formed of a single word and only happen at the beginning
1913 /// of a dotted-name.
1915 public class SimpleName : Expression {
1917 public readonly TypeArguments Arguments;
1920 public SimpleName (string name, Location l)
1926 public SimpleName (string name, TypeArguments args, Location l)
1933 public SimpleName (string name, TypeParameter[] type_params, Location l)
1938 Arguments = new TypeArguments (l);
1939 foreach (TypeParameter type_param in type_params)
1940 Arguments.Add (new TypeParameterExpr (type_param, l));
1943 public static string RemoveGenericArity (string name)
1946 StringBuilder sb = new StringBuilder ();
1947 while (start < name.Length) {
1948 int pos = name.IndexOf ('`', start);
1950 sb.Append (name.Substring (start));
1954 sb.Append (name.Substring (start, pos-start));
1957 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1963 return sb.ToString ();
1966 public SimpleName GetMethodGroup ()
1968 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1971 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1973 if (ec.IsFieldInitializer)
1974 Report.Error (236, l,
1975 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1979 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1983 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1985 return resolved_to != null && resolved_to.Type != null &&
1986 resolved_to.Type.Name == Name &&
1987 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1990 public override Expression DoResolve (EmitContext ec)
1992 return SimpleNameResolve (ec, null, false);
1995 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1997 return SimpleNameResolve (ec, right_side, false);
2001 public Expression DoResolve (EmitContext ec, bool intermediate)
2003 return SimpleNameResolve (ec, null, intermediate);
2006 private bool IsNestedChild (Type t, Type parent)
2011 while (parent != null) {
2012 parent = TypeManager.DropGenericTypeArguments (parent);
2013 if (TypeManager.IsNestedChildOf (t, parent))
2016 parent = parent.BaseType;
2022 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2024 if (!t.IsGenericTypeDefinition)
2027 DeclSpace ds = ec.DeclContainer;
2028 while (ds != null) {
2029 if (IsNestedChild (t, ds.TypeBuilder))
2038 Type[] gen_params = t.GetGenericArguments ();
2040 int arg_count = Arguments != null ? Arguments.Count : 0;
2042 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2043 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2044 TypeArguments new_args = new TypeArguments (loc);
2045 foreach (TypeParameter param in ds.TypeParameters)
2046 new_args.Add (new TypeParameterExpr (param, loc));
2048 if (Arguments != null)
2049 new_args.Add (Arguments);
2051 return new ConstructedType (t, new_args, loc);
2058 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2060 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2062 return fne.ResolveAsTypeStep (ec, silent);
2064 int errors = Report.Errors;
2065 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2068 if (fne.Type == null)
2071 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2073 return nested.ResolveAsTypeStep (ec, false);
2075 if (Arguments != null) {
2076 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2077 return ct.ResolveAsTypeStep (ec, false);
2083 if (silent || errors != Report.Errors)
2086 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2088 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2092 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2093 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2094 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2095 Type type = a.GetType (fullname);
2097 Report.SymbolRelatedToPreviousError (type);
2098 Expression.ErrorIsInaccesible (loc, fullname);
2103 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2107 // TODO: I am still not convinced about this. If someone else will need it
2108 // implement this as virtual property in MemberCore hierarchy
2109 string GetMemberType (MemberCore mc)
2111 if (mc is PropertyBase)
2115 if (mc is FieldBase)
2117 if (mc is MethodCore)
2119 if (mc is EnumMember)
2125 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2131 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2135 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2142 /// 7.5.2: Simple Names.
2144 /// Local Variables and Parameters are handled at
2145 /// parse time, so they never occur as SimpleNames.
2147 /// The `intermediate' flag is used by MemberAccess only
2148 /// and it is used to inform us that it is ok for us to
2149 /// avoid the static check, because MemberAccess might end
2150 /// up resolving the Name as a Type name and the access as
2151 /// a static type access.
2153 /// ie: Type Type; .... { Type.GetType (""); }
2155 /// Type is both an instance variable and a Type; Type.GetType
2156 /// is the static method not an instance method of type.
2158 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2160 Expression e = null;
2163 // Stage 1: Performed by the parser (binding to locals or parameters).
2165 Block current_block = ec.CurrentBlock;
2166 if (current_block != null){
2167 LocalInfo vi = current_block.GetLocalInfo (Name);
2169 if (Arguments != null) {
2170 Report.Error (307, loc,
2171 "The variable `{0}' cannot be used with type arguments",
2176 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2177 if (right_side != null) {
2178 return var.ResolveLValue (ec, right_side, loc);
2180 ResolveFlags rf = ResolveFlags.VariableOrValue;
2182 rf |= ResolveFlags.DisableFlowAnalysis;
2183 return var.Resolve (ec, rf);
2187 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2189 if (Arguments != null) {
2190 Report.Error (307, loc,
2191 "The variable `{0}' cannot be used with type arguments",
2196 if (right_side != null)
2197 return pref.ResolveLValue (ec, right_side, loc);
2199 return pref.Resolve (ec);
2204 // Stage 2: Lookup members
2207 DeclSpace lookup_ds = ec.DeclContainer;
2208 Type almost_matched_type = null;
2209 ArrayList almost_matched = null;
2211 if (lookup_ds.TypeBuilder == null)
2214 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2218 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2219 almost_matched_type = lookup_ds.TypeBuilder;
2220 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2223 lookup_ds =lookup_ds.Parent;
2224 } while (lookup_ds != null);
2226 if (e == null && ec.ContainerType != null)
2227 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2230 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2231 almost_matched_type = ec.ContainerType;
2232 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2234 e = ResolveAsTypeStep (ec, true);
2238 if (almost_matched != null)
2239 almostMatchedMembers = almost_matched;
2240 if (almost_matched_type == null)
2241 almost_matched_type = ec.ContainerType;
2242 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2246 if (e is TypeExpr) {
2247 if (Arguments == null)
2250 ConstructedType ct = new ConstructedType (
2251 (FullNamedExpression) e, Arguments, loc);
2252 return ct.ResolveAsTypeStep (ec, false);
2255 if (e is MemberExpr) {
2256 MemberExpr me = (MemberExpr) e;
2259 if (me.IsInstance) {
2260 if (ec.IsStatic || ec.IsFieldInitializer) {
2262 // Note that an MemberExpr can be both IsInstance and IsStatic.
2263 // An unresolved MethodGroupExpr can contain both kinds of methods
2264 // and each predicate is true if the MethodGroupExpr contains
2265 // at least one of that kind of method.
2269 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2270 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2271 return EmptyExpression.Null;
2275 // Pass the buck to MemberAccess and Invocation.
2277 left = EmptyExpression.Null;
2279 left = ec.GetThis (loc);
2282 left = new TypeExpression (ec.ContainerType, loc);
2285 e = me.ResolveMemberAccess (ec, left, loc, null);
2289 me = e as MemberExpr;
2293 if (Arguments != null) {
2294 MethodGroupExpr mg = me as MethodGroupExpr;
2298 return mg.ResolveGeneric (ec, Arguments);
2302 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2303 me.InstanceExpression.Type != me.DeclaringType &&
2304 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2305 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2306 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2307 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2311 return (right_side != null)
2312 ? me.DoResolveLValue (ec, right_side)
2313 : me.DoResolve (ec);
2319 public override void Emit (EmitContext ec)
2322 // If this is ever reached, then we failed to
2323 // find the name as a namespace
2326 Error (103, "The name `" + Name +
2327 "' does not exist in the class `" +
2328 ec.DeclContainer.Name + "'");
2331 public override string ToString ()
2336 public override string GetSignatureForError ()
2343 /// Represents a namespace or a type. The name of the class was inspired by
2344 /// section 10.8.1 (Fully Qualified Names).
2346 public abstract class FullNamedExpression : Expression {
2347 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2352 public abstract string FullName {
2358 /// Expression that evaluates to a type
2360 public abstract class TypeExpr : FullNamedExpression {
2361 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2363 TypeExpr t = DoResolveAsTypeStep (ec);
2367 eclass = ExprClass.Type;
2371 override public Expression DoResolve (EmitContext ec)
2373 return ResolveAsTypeTerminal (ec, false);
2376 override public void Emit (EmitContext ec)
2378 throw new Exception ("Should never be called");
2381 public virtual bool CheckAccessLevel (DeclSpace ds)
2383 return ds.CheckAccessLevel (Type);
2386 public virtual bool AsAccessible (DeclSpace ds, int flags)
2388 return ds.AsAccessible (Type, flags);
2391 public virtual bool IsClass {
2392 get { return Type.IsClass; }
2395 public virtual bool IsValueType {
2396 get { return Type.IsValueType; }
2399 public virtual bool IsInterface {
2400 get { return Type.IsInterface; }
2403 public virtual bool IsSealed {
2404 get { return Type.IsSealed; }
2407 public virtual bool CanInheritFrom ()
2409 if (Type == TypeManager.enum_type ||
2410 (Type == TypeManager.value_type && RootContext.StdLib) ||
2411 Type == TypeManager.multicast_delegate_type ||
2412 Type == TypeManager.delegate_type ||
2413 Type == TypeManager.array_type)
2419 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2421 public abstract string Name {
2425 public override bool Equals (object obj)
2427 TypeExpr tobj = obj as TypeExpr;
2431 return Type == tobj.Type;
2434 public override int GetHashCode ()
2436 return Type.GetHashCode ();
2439 public override string ToString ()
2446 /// Fully resolved Expression that already evaluated to a type
2448 public class TypeExpression : TypeExpr {
2449 public TypeExpression (Type t, Location l)
2452 eclass = ExprClass.Type;
2456 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2461 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2466 public override string Name {
2467 get { return Type.ToString (); }
2470 public override string FullName {
2471 get { return Type.FullName; }
2476 /// Used to create types from a fully qualified name. These are just used
2477 /// by the parser to setup the core types. A TypeLookupExpression is always
2478 /// classified as a type.
2480 public sealed class TypeLookupExpression : TypeExpr {
2481 readonly string name;
2483 public TypeLookupExpression (string name)
2486 eclass = ExprClass.Type;
2489 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2491 // It's null for corlib compilation only
2493 return DoResolveAsTypeStep (ec);
2498 static readonly char [] dot_array = { '.' };
2499 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2501 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2503 string lookup_name = name;
2504 int pos = name.IndexOf ('.');
2506 rest = name.Substring (pos + 1);
2507 lookup_name = name.Substring (0, pos);
2510 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2512 if (resolved != null && rest != null) {
2513 // Now handle the rest of the the name.
2514 string [] elements = rest.Split (dot_array);
2516 int count = elements.Length;
2518 while (i < count && resolved != null && resolved is Namespace) {
2519 Namespace ns = resolved as Namespace;
2520 element = elements [i++];
2521 lookup_name += "." + element;
2522 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2525 if (resolved != null && resolved is TypeExpr) {
2526 Type t = ((TypeExpr) resolved).Type;
2528 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2530 lookup_name = t.FullName;
2537 t = TypeManager.GetNestedType (t, elements [i++]);
2542 if (resolved == null) {
2543 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2547 if (!(resolved is TypeExpr)) {
2548 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2552 type = resolved.Type;
2556 public override string Name {
2557 get { return name; }
2560 public override string FullName {
2561 get { return name; }
2566 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2569 public class UnboundTypeExpression : TypeExpr
2573 public UnboundTypeExpression (MemberName name, Location l)
2579 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2582 if (name.Left != null) {
2583 Expression lexpr = name.Left.GetTypeExpression ();
2584 expr = new MemberAccess (lexpr, name.Basename);
2586 expr = new SimpleName (name.Basename, loc);
2589 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2594 return new TypeExpression (type, loc);
2597 public override string Name {
2598 get { return name.FullName; }
2601 public override string FullName {
2602 get { return name.FullName; }
2606 public class TypeAliasExpression : TypeExpr {
2607 FullNamedExpression alias;
2612 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2618 eclass = ExprClass.Type;
2620 name = alias.FullName + "<" + args.ToString () + ">";
2622 name = alias.FullName;
2625 public override string Name {
2626 get { return alias.FullName; }
2629 public override string FullName {
2630 get { return name; }
2633 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2635 texpr = alias.ResolveAsTypeTerminal (ec, false);
2639 Type type = texpr.Type;
2640 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2643 if (num_args == 0) {
2644 Report.Error (308, loc,
2645 "The non-generic type `{0}' cannot " +
2646 "be used with type arguments.",
2647 TypeManager.CSharpName (type));
2651 ConstructedType ctype = new ConstructedType (type, args, loc);
2652 return ctype.ResolveAsTypeTerminal (ec, false);
2653 } else if (num_args > 0) {
2654 Report.Error (305, loc,
2655 "Using the generic type `{0}' " +
2656 "requires {1} type arguments",
2657 TypeManager.CSharpName (type), num_args.ToString ());
2664 public override bool CheckAccessLevel (DeclSpace ds)
2666 return texpr.CheckAccessLevel (ds);
2669 public override bool AsAccessible (DeclSpace ds, int flags)
2671 return texpr.AsAccessible (ds, flags);
2674 public override bool IsClass {
2675 get { return texpr.IsClass; }
2678 public override bool IsValueType {
2679 get { return texpr.IsValueType; }
2682 public override bool IsInterface {
2683 get { return texpr.IsInterface; }
2686 public override bool IsSealed {
2687 get { return texpr.IsSealed; }
2692 /// This class denotes an expression which evaluates to a member
2693 /// of a struct or a class.
2695 public abstract class MemberExpr : Expression
2698 /// The name of this member.
2700 public abstract string Name {
2705 /// Whether this is an instance member.
2707 public abstract bool IsInstance {
2712 /// Whether this is a static member.
2714 public abstract bool IsStatic {
2719 /// The type which declares this member.
2721 public abstract Type DeclaringType {
2726 /// The instance expression associated with this member, if it's a
2727 /// non-static member.
2729 public Expression InstanceExpression;
2731 public static void error176 (Location loc, string name)
2733 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2734 "with an instance reference, qualify it with a type name instead", name);
2737 // TODO: possible optimalization
2738 // Cache resolved constant result in FieldBuilder <-> expression map
2739 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2740 SimpleName original)
2744 // original == null || original.Resolve (...) ==> left
2747 if (left is TypeExpr) {
2749 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2757 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2760 error176 (loc, GetSignatureForError ());
2764 InstanceExpression = left;
2769 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2774 if (InstanceExpression == EmptyExpression.Null) {
2775 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2779 if (InstanceExpression.Type.IsValueType) {
2780 if (InstanceExpression is IMemoryLocation) {
2781 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2783 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2784 InstanceExpression.Emit (ec);
2786 t.AddressOf (ec, AddressOp.Store);
2789 InstanceExpression.Emit (ec);
2791 if (prepare_for_load)
2792 ec.ig.Emit (OpCodes.Dup);
2797 /// MethodGroup Expression.
2799 /// This is a fully resolved expression that evaluates to a type
2801 public class MethodGroupExpr : MemberExpr {
2802 public MethodBase [] Methods;
2803 bool has_type_arguments = false;
2804 bool identical_type_name = false;
2807 public MethodGroupExpr (MemberInfo [] mi, Location l)
2809 Methods = new MethodBase [mi.Length];
2810 mi.CopyTo (Methods, 0);
2811 eclass = ExprClass.MethodGroup;
2812 type = TypeManager.object_type;
2816 public MethodGroupExpr (ArrayList list, Location l)
2818 Methods = new MethodBase [list.Count];
2821 list.CopyTo (Methods, 0);
2823 foreach (MemberInfo m in list){
2824 if (!(m is MethodBase)){
2825 Console.WriteLine ("Name " + m.Name);
2826 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2833 eclass = ExprClass.MethodGroup;
2834 type = TypeManager.object_type;
2837 public override Type DeclaringType {
2840 // We assume that the top-level type is in the end
2842 return Methods [Methods.Length - 1].DeclaringType;
2843 //return Methods [0].DeclaringType;
2847 public bool HasTypeArguments {
2849 return has_type_arguments;
2853 has_type_arguments = value;
2857 public bool IdenticalTypeName {
2859 return identical_type_name;
2863 identical_type_name = value;
2867 public bool IsBase {
2876 public override string GetSignatureForError ()
2878 return TypeManager.CSharpSignature (Methods [0]);
2881 public override string Name {
2883 return Methods [0].Name;
2887 public override bool IsInstance {
2889 foreach (MethodBase mb in Methods)
2897 public override bool IsStatic {
2899 foreach (MethodBase mb in Methods)
2907 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2908 SimpleName original)
2910 if (!(left is TypeExpr) &&
2911 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2912 IdenticalTypeName = true;
2914 return base.ResolveMemberAccess (ec, left, loc, original);
2917 override public Expression DoResolve (EmitContext ec)
2920 InstanceExpression = null;
2922 if (InstanceExpression != null) {
2923 InstanceExpression = InstanceExpression.DoResolve (ec);
2924 if (InstanceExpression == null)
2931 public void ReportUsageError ()
2933 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2934 Name + "()' is referenced without parentheses");
2937 override public void Emit (EmitContext ec)
2939 ReportUsageError ();
2942 bool RemoveMethods (bool keep_static)
2944 ArrayList smethods = new ArrayList ();
2946 foreach (MethodBase mb in Methods){
2947 if (mb.IsStatic == keep_static)
2951 if (smethods.Count == 0)
2954 Methods = new MethodBase [smethods.Count];
2955 smethods.CopyTo (Methods, 0);
2961 /// Removes any instance methods from the MethodGroup, returns
2962 /// false if the resulting set is empty.
2964 public bool RemoveInstanceMethods ()
2966 return RemoveMethods (true);
2970 /// Removes any static methods from the MethodGroup, returns
2971 /// false if the resulting set is empty.
2973 public bool RemoveStaticMethods ()
2975 return RemoveMethods (false);
2978 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2980 if (args.Resolve (ec) == false)
2983 Type[] atypes = args.Arguments;
2985 int first_count = 0;
2986 MethodInfo first = null;
2988 ArrayList list = new ArrayList ();
2989 foreach (MethodBase mb in Methods) {
2990 MethodInfo mi = mb as MethodInfo;
2991 if ((mi == null) || !mi.IsGenericMethod)
2994 Type[] gen_params = mi.GetGenericArguments ();
2996 if (first == null) {
2998 first_count = gen_params.Length;
3001 if (gen_params.Length != atypes.Length)
3004 list.Add (mi.MakeGenericMethod (atypes));
3007 if (list.Count > 0) {
3008 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3009 new_mg.InstanceExpression = InstanceExpression;
3010 new_mg.HasTypeArguments = true;
3011 new_mg.IsBase = IsBase;
3017 305, loc, "Using the generic method `{0}' " +
3018 "requires {1} type arguments", Name,
3019 first_count.ToString ());
3022 308, loc, "The non-generic method `{0}' " +
3023 "cannot be used with type arguments", Name);
3030 /// Fully resolved expression that evaluates to a Field
3032 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3033 public readonly FieldInfo FieldInfo;
3034 VariableInfo variable_info;
3036 LocalTemporary temp;
3038 bool in_initializer;
3040 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3043 this.in_initializer = in_initializer;
3046 public FieldExpr (FieldInfo fi, Location l)
3049 eclass = ExprClass.Variable;
3050 type = TypeManager.TypeToCoreType (fi.FieldType);
3054 public override string Name {
3056 return FieldInfo.Name;
3060 public override bool IsInstance {
3062 return !FieldInfo.IsStatic;
3066 public override bool IsStatic {
3068 return FieldInfo.IsStatic;
3072 public override Type DeclaringType {
3074 return FieldInfo.DeclaringType;
3078 public override string GetSignatureForError ()
3080 return TypeManager.GetFullNameSignature (FieldInfo);
3083 public VariableInfo VariableInfo {
3085 return variable_info;
3089 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3090 SimpleName original)
3092 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3094 Type t = fi.FieldType;
3096 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3097 IConstant ic = TypeManager.GetConstant (fi);
3100 ic = new ExternalConstant (fi);
3102 ic = ExternalConstant.CreateDecimal (fi);
3104 return base.ResolveMemberAccess (ec, left, loc, original);
3107 TypeManager.RegisterConstant (fi, ic);
3110 bool left_is_type = left is TypeExpr;
3111 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3112 Report.SymbolRelatedToPreviousError (FieldInfo);
3113 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3117 if (ic.ResolveValue ()) {
3118 if (!ec.IsInObsoleteScope)
3119 ic.CheckObsoleteness (loc);
3125 if (t.IsPointer && !ec.InUnsafe) {
3130 return base.ResolveMemberAccess (ec, left, loc, original);
3133 override public Expression DoResolve (EmitContext ec)
3135 return DoResolve (ec, false, false);
3138 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3140 if (!FieldInfo.IsStatic){
3141 if (InstanceExpression == null){
3143 // This can happen when referencing an instance field using
3144 // a fully qualified type expression: TypeName.InstanceField = xxx
3146 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3150 // Resolve the field's instance expression while flow analysis is turned
3151 // off: when accessing a field "a.b", we must check whether the field
3152 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3154 if (lvalue_instance) {
3155 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3156 Expression right_side =
3157 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3158 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3161 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3162 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3165 if (InstanceExpression == null)
3168 InstanceExpression.CheckMarshalByRefAccess ();
3171 if (!in_initializer && !ec.IsFieldInitializer) {
3172 ObsoleteAttribute oa;
3173 FieldBase f = TypeManager.GetField (FieldInfo);
3175 if (!ec.IsInObsoleteScope)
3176 f.CheckObsoleteness (loc);
3178 // To be sure that type is external because we do not register generated fields
3179 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3180 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3182 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3186 AnonymousContainer am = ec.CurrentAnonymousMethod;
3188 if (!FieldInfo.IsStatic){
3189 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3190 Report.Error (1673, loc,
3191 "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",
3195 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3196 ec.CaptureField (this);
3200 // If the instance expression is a local variable or parameter.
3201 IVariable var = InstanceExpression as IVariable;
3202 if ((var == null) || (var.VariableInfo == null))
3205 VariableInfo vi = var.VariableInfo;
3206 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3209 variable_info = vi.GetSubStruct (FieldInfo.Name);
3213 static readonly int [] codes = {
3214 191, // instance, write access
3215 192, // instance, out access
3216 198, // static, write access
3217 199, // static, out access
3218 1648, // member of value instance, write access
3219 1649, // member of value instance, out access
3220 1650, // member of value static, write access
3221 1651 // member of value static, out access
3224 static readonly string [] msgs = {
3225 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3226 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3227 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3228 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3229 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3230 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3231 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3232 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3235 // The return value is always null. Returning a value simplifies calling code.
3236 Expression Report_AssignToReadonly (Expression right_side)
3239 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3243 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3245 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3250 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3252 IVariable var = InstanceExpression as IVariable;
3253 if ((var != null) && (var.VariableInfo != null))
3254 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3256 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3257 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3259 Expression e = DoResolve (ec, lvalue_instance, out_access);
3264 FieldBase fb = TypeManager.GetField (FieldInfo);
3268 if (FieldInfo.IsInitOnly) {
3269 // InitOnly fields can only be assigned in constructors or initializers
3270 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3271 return Report_AssignToReadonly (right_side);
3273 if (ec.IsConstructor) {
3274 Type ctype = ec.TypeContainer.CurrentType;
3276 ctype = ec.ContainerType;
3278 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3279 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3280 return Report_AssignToReadonly (right_side);
3281 // static InitOnly fields cannot be assigned-to in an instance constructor
3282 if (IsStatic && !ec.IsStatic)
3283 return Report_AssignToReadonly (right_side);
3284 // instance constructors can't modify InitOnly fields of other instances of the same type
3285 if (!IsStatic && !(InstanceExpression is This))
3286 return Report_AssignToReadonly (right_side);
3290 if (right_side == EmptyExpression.OutAccess &&
3291 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3292 Report.SymbolRelatedToPreviousError (DeclaringType);
3293 Report.Warning (197, 1, loc,
3294 "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",
3295 GetSignatureForError ());
3301 public override void CheckMarshalByRefAccess ()
3303 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3304 Report.SymbolRelatedToPreviousError (DeclaringType);
3305 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",
3306 GetSignatureForError ());
3310 public bool VerifyFixed ()
3312 IVariable variable = InstanceExpression as IVariable;
3313 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3314 // We defer the InstanceExpression check after the variable check to avoid a
3315 // separate null check on InstanceExpression.
3316 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3319 public override int GetHashCode ()
3321 return FieldInfo.GetHashCode ();
3324 public override bool Equals (object obj)
3326 FieldExpr fe = obj as FieldExpr;
3330 if (FieldInfo != fe.FieldInfo)
3333 if (InstanceExpression == null || fe.InstanceExpression == null)
3336 return InstanceExpression.Equals (fe.InstanceExpression);
3339 public void Emit (EmitContext ec, bool leave_copy)
3341 ILGenerator ig = ec.ig;
3342 bool is_volatile = false;
3344 FieldBase f = TypeManager.GetField (FieldInfo);
3346 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3349 f.SetMemberIsUsed ();
3352 if (FieldInfo.IsStatic){
3354 ig.Emit (OpCodes.Volatile);
3356 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3359 EmitInstance (ec, false);
3362 ig.Emit (OpCodes.Volatile);
3364 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3367 ig.Emit (OpCodes.Ldflda, FieldInfo);
3368 ig.Emit (OpCodes.Ldflda, ff.Element);
3371 ig.Emit (OpCodes.Ldfld, FieldInfo);
3376 ec.ig.Emit (OpCodes.Dup);
3377 if (!FieldInfo.IsStatic) {
3378 temp = new LocalTemporary (this.Type);
3384 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3386 FieldAttributes fa = FieldInfo.Attributes;
3387 bool is_static = (fa & FieldAttributes.Static) != 0;
3388 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3389 ILGenerator ig = ec.ig;
3390 prepared = prepare_for_load;
3392 if (is_readonly && !ec.IsConstructor){
3393 Report_AssignToReadonly (source);
3397 EmitInstance (ec, prepare_for_load);
3401 ec.ig.Emit (OpCodes.Dup);
3402 if (!FieldInfo.IsStatic) {
3403 temp = new LocalTemporary (this.Type);
3408 FieldBase f = TypeManager.GetField (FieldInfo);
3410 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3411 ig.Emit (OpCodes.Volatile);
3417 ig.Emit (OpCodes.Stsfld, FieldInfo);
3419 ig.Emit (OpCodes.Stfld, FieldInfo);
3427 public override void Emit (EmitContext ec)
3432 public void AddressOf (EmitContext ec, AddressOp mode)
3434 ILGenerator ig = ec.ig;
3436 FieldBase f = TypeManager.GetField (FieldInfo);
3438 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3439 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3440 f.GetSignatureForError ());
3444 if ((mode & AddressOp.Store) != 0)
3446 if ((mode & AddressOp.Load) != 0)
3447 f.SetMemberIsUsed ();
3451 // Handle initonly fields specially: make a copy and then
3452 // get the address of the copy.
3455 if (FieldInfo.IsInitOnly){
3457 if (ec.IsConstructor){
3458 if (FieldInfo.IsStatic){
3470 local = ig.DeclareLocal (type);
3471 ig.Emit (OpCodes.Stloc, local);
3472 ig.Emit (OpCodes.Ldloca, local);
3477 if (FieldInfo.IsStatic){
3478 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3481 EmitInstance (ec, false);
3482 ig.Emit (OpCodes.Ldflda, FieldInfo);
3488 // A FieldExpr whose address can not be taken
3490 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3491 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3495 public new void AddressOf (EmitContext ec, AddressOp mode)
3497 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3502 /// Expression that evaluates to a Property. The Assign class
3503 /// might set the `Value' expression if we are in an assignment.
3505 /// This is not an LValue because we need to re-write the expression, we
3506 /// can not take data from the stack and store it.
3508 public class PropertyExpr : MemberExpr, IAssignMethod {
3509 public readonly PropertyInfo PropertyInfo;
3512 // This is set externally by the `BaseAccess' class
3515 MethodInfo getter, setter;
3520 LocalTemporary temp;
3523 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3525 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3528 eclass = ExprClass.PropertyAccess;
3532 type = TypeManager.TypeToCoreType (pi.PropertyType);
3534 ResolveAccessors (containerType);
3537 public override string Name {
3539 return PropertyInfo.Name;
3543 public override bool IsInstance {
3549 public override bool IsStatic {
3555 public override Type DeclaringType {
3557 return PropertyInfo.DeclaringType;
3561 public override string GetSignatureForError ()
3563 return TypeManager.GetFullNameSignature (PropertyInfo);
3566 void FindAccessors (Type invocation_type)
3568 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3569 BindingFlags.Static | BindingFlags.Instance |
3570 BindingFlags.DeclaredOnly;
3572 Type current = PropertyInfo.DeclaringType;
3573 for (; current != null; current = current.BaseType) {
3574 MemberInfo[] group = TypeManager.MemberLookup (
3575 invocation_type, invocation_type, current,
3576 MemberTypes.Property, flags, PropertyInfo.Name, null);
3581 if (group.Length != 1)
3582 // Oooops, can this ever happen ?
3585 PropertyInfo pi = (PropertyInfo) group [0];
3588 getter = pi.GetGetMethod (true);
3591 setter = pi.GetSetMethod (true);
3593 MethodInfo accessor = getter != null ? getter : setter;
3595 if (!accessor.IsVirtual)
3601 // We also perform the permission checking here, as the PropertyInfo does not
3602 // hold the information for the accessibility of its setter/getter
3604 // TODO: can use TypeManager.GetProperty to boost performance
3605 void ResolveAccessors (Type containerType)
3607 FindAccessors (containerType);
3609 if (getter != null) {
3610 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3611 IMethodData md = TypeManager.GetMethod (the_getter);
3613 md.SetMemberIsUsed ();
3615 AccessorTable [getter] = PropertyInfo;
3616 is_static = getter.IsStatic;
3619 if (setter != null) {
3620 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3621 IMethodData md = TypeManager.GetMethod (the_setter);
3623 md.SetMemberIsUsed ();
3625 AccessorTable [setter] = PropertyInfo;
3626 is_static = setter.IsStatic;
3630 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3633 InstanceExpression = null;
3637 if (InstanceExpression == null) {
3638 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3642 if (lvalue_instance)
3643 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3645 InstanceExpression = InstanceExpression.DoResolve (ec);
3646 if (InstanceExpression == null)
3649 InstanceExpression.CheckMarshalByRefAccess ();
3651 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
3652 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
3653 TypeManager.IsFamilyAccessible (ec.ContainerType, PropertyInfo.DeclaringType) &&
3654 !TypeManager.IsFamilyAccessible (InstanceExpression.Type, ec.ContainerType)) {
3655 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3662 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3664 // TODO: correctly we should compare arguments but it will lead to bigger changes
3665 if (mi is MethodBuilder) {
3666 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3670 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3672 ParameterData iparams = TypeManager.GetParameterData (mi);
3673 sig.Append (getter ? "get_" : "set_");
3675 sig.Append (iparams.GetSignatureForError ());
3677 Report.SymbolRelatedToPreviousError (mi);
3678 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3679 Name, sig.ToString ());
3682 override public Expression DoResolve (EmitContext ec)
3687 if (getter != null){
3688 if (TypeManager.GetParameterData (getter).Count != 0){
3689 Error_PropertyNotFound (getter, true);
3694 if (getter == null){
3696 // The following condition happens if the PropertyExpr was
3697 // created, but is invalid (ie, the property is inaccessible),
3698 // and we did not want to embed the knowledge about this in
3699 // the caller routine. This only avoids double error reporting.
3704 if (InstanceExpression != EmptyExpression.Null) {
3705 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3706 TypeManager.GetFullNameSignature (PropertyInfo));
3711 bool must_do_cs1540_check = false;
3712 if (getter != null &&
3713 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3714 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3715 if (pm != null && pm.HasCustomAccessModifier) {
3716 Report.SymbolRelatedToPreviousError (pm);
3717 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3718 TypeManager.CSharpSignature (getter));
3721 Report.SymbolRelatedToPreviousError (getter);
3722 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3727 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3731 // Only base will allow this invocation to happen.
3733 if (IsBase && getter.IsAbstract) {
3734 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3738 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3748 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3750 if (right_side == EmptyExpression.OutAccess) {
3751 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3752 GetSignatureForError ());
3756 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3757 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3758 GetSignatureForError ());
3762 if (setter == null){
3764 // The following condition happens if the PropertyExpr was
3765 // created, but is invalid (ie, the property is inaccessible),
3766 // and we did not want to embed the knowledge about this in
3767 // the caller routine. This only avoids double error reporting.
3771 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3772 GetSignatureForError ());
3776 if (TypeManager.GetParameterData (setter).Count != 1){
3777 Error_PropertyNotFound (setter, false);
3781 bool must_do_cs1540_check;
3782 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3783 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3784 if (pm != null && pm.HasCustomAccessModifier) {
3785 Report.SymbolRelatedToPreviousError (pm);
3786 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3787 TypeManager.CSharpSignature (setter));
3790 Report.SymbolRelatedToPreviousError (setter);
3791 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3796 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3800 // Only base will allow this invocation to happen.
3802 if (IsBase && setter.IsAbstract){
3803 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3810 public override void Emit (EmitContext ec)
3815 public void Emit (EmitContext ec, bool leave_copy)
3818 // Special case: length of single dimension array property is turned into ldlen
3820 if ((getter == TypeManager.system_int_array_get_length) ||
3821 (getter == TypeManager.int_array_get_length)){
3822 Type iet = InstanceExpression.Type;
3825 // System.Array.Length can be called, but the Type does not
3826 // support invoking GetArrayRank, so test for that case first
3828 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3830 EmitInstance (ec, false);
3831 ec.ig.Emit (OpCodes.Ldlen);
3832 ec.ig.Emit (OpCodes.Conv_I4);
3837 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3840 ec.ig.Emit (OpCodes.Dup);
3842 temp = new LocalTemporary (this.Type);
3849 // Implements the IAssignMethod interface for assignments
3851 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3853 Expression my_source = source;
3855 prepared = prepare_for_load;
3860 ec.ig.Emit (OpCodes.Dup);
3862 temp = new LocalTemporary (this.Type);
3866 } else if (leave_copy) {
3869 temp = new LocalTemporary (this.Type);
3875 ArrayList args = new ArrayList (1);
3876 args.Add (new Argument (my_source, Argument.AType.Expression));
3878 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3888 /// Fully resolved expression that evaluates to an Event
3890 public class EventExpr : MemberExpr {
3891 public readonly EventInfo EventInfo;
3894 MethodInfo add_accessor, remove_accessor;
3896 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3898 public EventExpr (EventInfo ei, Location loc)
3902 eclass = ExprClass.EventAccess;
3904 add_accessor = TypeManager.GetAddMethod (ei);
3905 remove_accessor = TypeManager.GetRemoveMethod (ei);
3906 if (add_accessor != null)
3907 AccessorTable [add_accessor] = ei;
3908 if (remove_accessor != null)
3909 AccessorTable [remove_accessor] = ei;
3911 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3914 if (EventInfo is MyEventBuilder){
3915 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3916 type = eb.EventType;
3919 type = EventInfo.EventHandlerType;
3922 public override string Name {
3924 return EventInfo.Name;
3928 public override bool IsInstance {
3934 public override bool IsStatic {
3940 public override Type DeclaringType {
3942 return EventInfo.DeclaringType;
3946 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3947 SimpleName original)
3950 // If the event is local to this class, we transform ourselves into a FieldExpr
3953 if (EventInfo.DeclaringType == ec.ContainerType ||
3954 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3955 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3958 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3961 Report.Error (-200, loc, "Internal error!!");
3965 InstanceExpression = null;
3967 return ml.ResolveMemberAccess (ec, left, loc, original);
3971 return base.ResolveMemberAccess (ec, left, loc, original);
3975 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3978 InstanceExpression = null;
3982 if (InstanceExpression == null) {
3983 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3987 InstanceExpression = InstanceExpression.DoResolve (ec);
3988 if (InstanceExpression == null)
3992 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3993 // However, in the Event case, we reported a CS0122 instead.
3995 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3996 InstanceExpression.Type != ec.ContainerType &&
3997 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3998 Report.SymbolRelatedToPreviousError (EventInfo);
3999 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4006 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4008 return DoResolve (ec);
4011 public override Expression DoResolve (EmitContext ec)
4013 bool must_do_cs1540_check;
4014 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4015 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4016 Report.SymbolRelatedToPreviousError (EventInfo);
4017 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4021 if (!InstanceResolve (ec, must_do_cs1540_check))
4027 public override void Emit (EmitContext ec)
4029 if (InstanceExpression is This)
4030 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4032 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4033 "(except on the defining type)", Name);
4036 public override string GetSignatureForError ()
4038 return TypeManager.CSharpSignature (EventInfo);
4041 public void EmitAddOrRemove (EmitContext ec, Expression source)
4043 BinaryDelegate source_del = (BinaryDelegate) source;
4044 Expression handler = source_del.Right;
4046 Argument arg = new Argument (handler, Argument.AType.Expression);
4047 ArrayList args = new ArrayList ();
4051 if (source_del.IsAddition)
4052 Invocation.EmitCall (
4053 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4055 Invocation.EmitCall (
4056 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4061 public class TemporaryVariable : Expression, IMemoryLocation
4065 public TemporaryVariable (Type type, Location loc)
4069 eclass = ExprClass.Value;
4072 public override Expression DoResolve (EmitContext ec)
4077 TypeExpr te = new TypeExpression (type, loc);
4078 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4079 if (!li.Resolve (ec))
4082 AnonymousContainer am = ec.CurrentAnonymousMethod;
4083 if ((am != null) && am.IsIterator)
4084 ec.CaptureVariable (li);
4089 public override void Emit (EmitContext ec)
4091 ILGenerator ig = ec.ig;
4093 if (li.FieldBuilder != null) {
4094 ig.Emit (OpCodes.Ldarg_0);
4095 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
4097 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
4101 public void EmitLoadAddress (EmitContext ec)
4103 ILGenerator ig = ec.ig;
4105 if (li.FieldBuilder != null) {
4106 ig.Emit (OpCodes.Ldarg_0);
4107 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
4109 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
4113 public void Store (EmitContext ec, Expression right_side)
4115 if (li.FieldBuilder != null)
4116 ec.ig.Emit (OpCodes.Ldarg_0);
4118 right_side.Emit (ec);
4119 if (li.FieldBuilder != null) {
4120 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4122 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4126 public void EmitThis (EmitContext ec)
4128 if (li.FieldBuilder != null) {
4129 ec.ig.Emit (OpCodes.Ldarg_0);
4133 public void EmitStore (ILGenerator ig)
4135 if (li.FieldBuilder != null)
4136 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4138 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4141 public void AddressOf (EmitContext ec, AddressOp mode)
4143 EmitLoadAddress (ec);