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);
243 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
244 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
245 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
249 // Constrains don't need to be checked for overrides
250 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
251 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
256 ConstructedType ct = te as ConstructedType;
257 if ((ct != null) && !ct.CheckConstraints (ec))
263 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
265 int errors = Report.Errors;
267 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
272 if (fne.eclass != ExprClass.Type) {
273 if (!silent && errors == Report.Errors)
274 fne.Error_UnexpectedKind (null, "type", loc);
278 TypeExpr te = fne as TypeExpr;
280 if (!te.CheckAccessLevel (ec.DeclContainer)) {
281 Report.SymbolRelatedToPreviousError (te.Type);
282 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
290 public static void ErrorIsInaccesible (Location loc, string name)
292 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
295 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
297 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
298 + " The qualifier must be of type `{2}' or derived from it",
299 TypeManager.GetFullNameSignature (m),
300 TypeManager.CSharpName (qualifier),
301 TypeManager.CSharpName (container));
305 public static void Error_InvalidExpressionStatement (Location loc)
307 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
308 "expressions can be used as a statement");
311 public void Error_InvalidExpressionStatement ()
313 Error_InvalidExpressionStatement (loc);
316 protected void Error_CannotAssign (string to, string roContext)
318 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
322 public static void Error_VoidInvalidInTheContext (Location loc)
324 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
327 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
329 if (Type.FullName == target.FullName){
330 Report.ExtraInformation (loc,
332 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
333 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
338 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
339 GetSignatureForError (), TypeManager.CSharpName (target));
343 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
344 bool b = Convert.ExplicitNumericConversion (e, target) != null;
347 Convert.ExplicitReferenceConversionExists (Type, target) ||
348 Convert.ExplicitUnsafe (e, target) != null ||
349 (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null))
351 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
352 "An explicit conversion exists (are you missing a cast?)",
353 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
357 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
358 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
359 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
363 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
364 Type == TypeManager.anonymous_method_type ?
365 "anonymous method" : "`" + GetSignatureForError () + "'",
366 TypeManager.CSharpName (target));
369 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
371 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
372 TypeManager.CSharpName (type), name);
375 protected static void Error_ValueAssignment (Location loc)
377 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
380 ResolveFlags ExprClassToResolveFlags
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.Value:
392 case ExprClass.Variable:
393 case ExprClass.PropertyAccess:
394 case ExprClass.EventAccess:
395 case ExprClass.IndexerAccess:
396 return ResolveFlags.VariableOrValue;
399 throw new Exception ("Expression " + GetType () +
400 " ExprClass is Invalid after resolve");
406 /// Resolves an expression and performs semantic analysis on it.
410 /// Currently Resolve wraps DoResolve to perform sanity
411 /// checking and assertion checking on what we expect from Resolve.
413 public Expression Resolve (EmitContext ec, ResolveFlags flags)
415 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
416 return ResolveAsTypeStep (ec, false);
418 bool do_flow_analysis = ec.DoFlowAnalysis;
419 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
420 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
421 do_flow_analysis = false;
422 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
423 omit_struct_analysis = true;
426 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
427 if (this is SimpleName) {
428 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
429 e = ((SimpleName) this).DoResolve (ec, intermediate);
438 if ((flags & e.ExprClassToResolveFlags) == 0) {
439 e.Error_UnexpectedKind (flags, loc);
443 if (e.type == null && !(e is Namespace)) {
444 throw new Exception (
445 "Expression " + e.GetType () +
446 " did not set its type after Resolve\n" +
447 "called from: " + this.GetType ());
454 /// Resolves an expression and performs semantic analysis on it.
456 public Expression Resolve (EmitContext ec)
458 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
460 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
461 ((MethodGroupExpr) e).ReportUsageError ();
467 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
469 Expression e = Resolve (ec);
473 Constant c = e as Constant;
477 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
482 /// Resolves an expression for LValue assignment
486 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
487 /// checking and assertion checking on what we expect from Resolve
489 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
491 int errors = Report.Errors;
492 bool out_access = right_side == EmptyExpression.OutAccess;
494 Expression e = DoResolveLValue (ec, right_side);
496 if (e != null && out_access && !(e is IMemoryLocation)) {
497 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
498 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
500 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
501 // e.GetType () + " " + e.GetSignatureForError ());
506 if (errors == Report.Errors) {
508 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
510 Error_ValueAssignment (loc);
515 if (e.eclass == ExprClass.Invalid)
516 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
518 if (e.eclass == ExprClass.MethodGroup) {
519 ((MethodGroupExpr) e).ReportUsageError ();
523 if ((e.type == null) && !(e is ConstructedType))
524 throw new Exception ("Expression " + e + " did not set its type after Resolve");
530 /// Emits the code for the expression
534 /// The Emit method is invoked to generate the code
535 /// for the expression.
537 public abstract void Emit (EmitContext ec);
539 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
542 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
546 /// Protected constructor. Only derivate types should
547 /// be able to be created
550 protected Expression ()
552 eclass = ExprClass.Invalid;
557 /// Returns a fully formed expression after a MemberLookup
560 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
563 return new EventExpr ((EventInfo) mi, loc);
564 else if (mi is FieldInfo)
565 return new FieldExpr ((FieldInfo) mi, loc);
566 else if (mi is PropertyInfo)
567 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
568 else if (mi is Type){
569 return new TypeExpression ((System.Type) mi, loc);
575 protected static ArrayList almostMatchedMembers = new ArrayList (4);
578 // FIXME: Probably implement a cache for (t,name,current_access_set)?
580 // This code could use some optimizations, but we need to do some
581 // measurements. For example, we could use a delegate to `flag' when
582 // something can not any longer be a method-group (because it is something
586 // If the return value is an Array, then it is an array of
589 // If the return value is an MemberInfo, it is anything, but a Method
593 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
594 // the arguments here and have MemberLookup return only the methods that
595 // match the argument count/type, unlike we are doing now (we delay this
598 // This is so we can catch correctly attempts to invoke instance methods
599 // from a static body (scan for error 120 in ResolveSimpleName).
602 // FIXME: Potential optimization, have a static ArrayList
605 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
606 MemberTypes mt, BindingFlags bf, Location loc)
608 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
612 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
613 // `qualifier_type' or null to lookup members in the current class.
616 public static Expression MemberLookup (Type container_type,
617 Type qualifier_type, Type queried_type,
618 string name, MemberTypes mt,
619 BindingFlags bf, Location loc)
621 almostMatchedMembers.Clear ();
623 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
624 queried_type, mt, bf, name, almostMatchedMembers);
630 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
631 MemberInfo non_method = null;
632 ArrayList methods = new ArrayList (2);
634 foreach (MemberInfo m in mi) {
635 if (m is MethodBase) {
640 if (non_method == null) {
645 Report.SymbolRelatedToPreviousError (m);
646 Report.SymbolRelatedToPreviousError (non_method);
647 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
648 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
652 if (methods.Count == 0)
655 if (non_method != null) {
656 MethodBase method = (MethodBase) methods [0];
658 if (method.DeclaringType == non_method.DeclaringType) {
659 // Cannot happen with C# code, but is valid in IL
660 Report.SymbolRelatedToPreviousError (method);
661 Report.SymbolRelatedToPreviousError (non_method);
662 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
663 TypeManager.GetFullNameSignature (non_method),
664 TypeManager.CSharpSignature (method));
669 Report.SymbolRelatedToPreviousError (method);
670 Report.SymbolRelatedToPreviousError (non_method);
671 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
672 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
676 return new MethodGroupExpr (methods, loc);
679 if (mi [0] is MethodBase)
680 return new MethodGroupExpr (mi, loc);
682 return ExprClassFromMemberInfo (container_type, mi [0], loc);
685 public const MemberTypes AllMemberTypes =
686 MemberTypes.Constructor |
690 MemberTypes.NestedType |
691 MemberTypes.Property;
693 public const BindingFlags AllBindingFlags =
694 BindingFlags.Public |
695 BindingFlags.Static |
696 BindingFlags.Instance;
698 public static Expression MemberLookup (Type container_type, Type queried_type,
699 string name, Location loc)
701 return MemberLookup (container_type, null, queried_type, name,
702 AllMemberTypes, AllBindingFlags, loc);
705 public static Expression MemberLookup (Type container_type, Type qualifier_type,
706 Type queried_type, string name, Location loc)
708 return MemberLookup (container_type, qualifier_type, queried_type,
709 name, AllMemberTypes, AllBindingFlags, loc);
712 public static Expression MethodLookup (Type container_type, Type queried_type,
713 string name, Location loc)
715 return MemberLookup (container_type, null, queried_type, name,
716 MemberTypes.Method, AllBindingFlags, loc);
720 /// This is a wrapper for MemberLookup that is not used to "probe", but
721 /// to find a final definition. If the final definition is not found, we
722 /// look for private members and display a useful debugging message if we
725 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
726 Type queried_type, string name, Location loc)
728 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
729 AllMemberTypes, AllBindingFlags, loc);
732 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
733 Type queried_type, string name,
734 MemberTypes mt, BindingFlags bf,
739 int errors = Report.Errors;
741 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
743 if (e == null && errors == Report.Errors)
744 // No errors were reported by MemberLookup, but there was an error.
745 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
750 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
751 Type queried_type, string name,
752 string class_name, bool complain_if_none_found,
755 if (almostMatchedMembers.Count != 0) {
756 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
757 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
758 for (int j = 0; j < i; ++j) {
759 if (m == almostMatchedMembers [j]) {
767 Type declaring_type = m.DeclaringType;
769 Report.SymbolRelatedToPreviousError (m);
770 if (qualifier_type == null) {
771 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
772 TypeManager.CSharpName (m.DeclaringType),
773 TypeManager.CSharpName (container_type));
775 } else if (qualifier_type != container_type &&
776 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
777 // Although a derived class can access protected members of
778 // its base class it cannot do so through an instance of the
779 // base class (CS1540). If the qualifier_type is a base of the
780 // ec.ContainerType and the lookup succeeds with the latter one,
781 // then we are in this situation.
782 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
784 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
787 almostMatchedMembers.Clear ();
791 MemberInfo[] lookup = null;
792 if (queried_type == null) {
793 class_name = "global::";
795 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
796 AllMemberTypes, AllBindingFlags |
797 BindingFlags.NonPublic, name, null);
800 if (lookup == null) {
801 if (!complain_if_none_found)
804 if (class_name != null)
805 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
808 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
812 if (TypeManager.MemberLookup (queried_type, null, queried_type,
813 AllMemberTypes, AllBindingFlags |
814 BindingFlags.NonPublic, name, null) == null) {
815 if ((lookup.Length == 1) && (lookup [0] is Type)) {
816 Type t = (Type) lookup [0];
818 Report.Error (305, loc,
819 "Using the generic type `{0}' " +
820 "requires {1} type arguments",
821 TypeManager.CSharpName (t),
822 TypeManager.GetNumberOfTypeArguments (t).ToString ());
827 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
828 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
829 if (name == ".ctor" && ml.Count == 0)
831 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
835 Report.SymbolRelatedToPreviousError (lookup [0]);
836 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
840 /// Returns an expression that can be used to invoke operator true
841 /// on the expression if it exists.
843 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
845 return GetOperatorTrueOrFalse (ec, e, true, loc);
849 /// Returns an expression that can be used to invoke operator false
850 /// on the expression if it exists.
852 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
854 return GetOperatorTrueOrFalse (ec, e, false, loc);
857 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
860 Expression operator_group;
863 if (TypeManager.IsNullableType (e.Type))
864 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
867 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc);
868 if (operator_group == null)
871 ArrayList arguments = new ArrayList ();
872 arguments.Add (new Argument (e, Argument.AType.Expression));
873 method = Invocation.OverloadResolve (
874 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
879 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
883 /// Resolves the expression `e' into a boolean expression: either through
884 /// an implicit conversion, or through an `operator true' invocation
886 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
892 if (e.Type == TypeManager.bool_type)
895 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
897 if (converted != null)
901 // If no implicit conversion to bool exists, try using `operator true'
903 converted = Expression.GetOperatorTrue (ec, e, loc);
904 if (converted == null){
905 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
911 public virtual string ExprClassName
915 case ExprClass.Invalid:
917 case ExprClass.Value:
919 case ExprClass.Variable:
921 case ExprClass.Namespace:
925 case ExprClass.MethodGroup:
926 return "method group";
927 case ExprClass.PropertyAccess:
928 return "property access";
929 case ExprClass.EventAccess:
930 return "event access";
931 case ExprClass.IndexerAccess:
932 return "indexer access";
933 case ExprClass.Nothing:
936 throw new Exception ("Should not happen");
941 /// Reports that we were expecting `expr' to be of class `expected'
943 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
945 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
948 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
950 string name = GetSignatureForError ();
952 name = ds.GetSignatureForError () + '.' + name;
954 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
955 name, was, expected);
958 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
960 string [] valid = new string [4];
963 if ((flags & ResolveFlags.VariableOrValue) != 0) {
964 valid [count++] = "variable";
965 valid [count++] = "value";
968 if ((flags & ResolveFlags.Type) != 0)
969 valid [count++] = "type";
971 if ((flags & ResolveFlags.MethodGroup) != 0)
972 valid [count++] = "method group";
975 valid [count++] = "unknown";
977 StringBuilder sb = new StringBuilder (valid [0]);
978 for (int i = 1; i < count - 1; i++) {
980 sb.Append (valid [i]);
983 sb.Append ("' or `");
984 sb.Append (valid [count - 1]);
987 Report.Error (119, loc,
988 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
991 public static void UnsafeError (Location loc)
993 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
997 // Load the object from the pointer.
999 public static void LoadFromPtr (ILGenerator ig, Type t)
1001 if (t == TypeManager.int32_type)
1002 ig.Emit (OpCodes.Ldind_I4);
1003 else if (t == TypeManager.uint32_type)
1004 ig.Emit (OpCodes.Ldind_U4);
1005 else if (t == TypeManager.short_type)
1006 ig.Emit (OpCodes.Ldind_I2);
1007 else if (t == TypeManager.ushort_type)
1008 ig.Emit (OpCodes.Ldind_U2);
1009 else if (t == TypeManager.char_type)
1010 ig.Emit (OpCodes.Ldind_U2);
1011 else if (t == TypeManager.byte_type)
1012 ig.Emit (OpCodes.Ldind_U1);
1013 else if (t == TypeManager.sbyte_type)
1014 ig.Emit (OpCodes.Ldind_I1);
1015 else if (t == TypeManager.uint64_type)
1016 ig.Emit (OpCodes.Ldind_I8);
1017 else if (t == TypeManager.int64_type)
1018 ig.Emit (OpCodes.Ldind_I8);
1019 else if (t == TypeManager.float_type)
1020 ig.Emit (OpCodes.Ldind_R4);
1021 else if (t == TypeManager.double_type)
1022 ig.Emit (OpCodes.Ldind_R8);
1023 else if (t == TypeManager.bool_type)
1024 ig.Emit (OpCodes.Ldind_I1);
1025 else if (t == TypeManager.intptr_type)
1026 ig.Emit (OpCodes.Ldind_I);
1027 else if (TypeManager.IsEnumType (t)) {
1028 if (t == TypeManager.enum_type)
1029 ig.Emit (OpCodes.Ldind_Ref);
1031 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1032 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1033 ig.Emit (OpCodes.Ldobj, t);
1034 else if (t.IsPointer)
1035 ig.Emit (OpCodes.Ldind_I);
1037 ig.Emit (OpCodes.Ldind_Ref);
1041 // The stack contains the pointer and the value of type `type'
1043 public static void StoreFromPtr (ILGenerator ig, Type type)
1045 if (TypeManager.IsEnumType (type))
1046 type = TypeManager.EnumToUnderlying (type);
1047 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1048 ig.Emit (OpCodes.Stind_I4);
1049 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1050 ig.Emit (OpCodes.Stind_I8);
1051 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1052 type == TypeManager.ushort_type)
1053 ig.Emit (OpCodes.Stind_I2);
1054 else if (type == TypeManager.float_type)
1055 ig.Emit (OpCodes.Stind_R4);
1056 else if (type == TypeManager.double_type)
1057 ig.Emit (OpCodes.Stind_R8);
1058 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1059 type == TypeManager.bool_type)
1060 ig.Emit (OpCodes.Stind_I1);
1061 else if (type == TypeManager.intptr_type)
1062 ig.Emit (OpCodes.Stind_I);
1063 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1064 ig.Emit (OpCodes.Stobj, type);
1066 ig.Emit (OpCodes.Stind_Ref);
1070 // Returns the size of type `t' if known, otherwise, 0
1072 public static int GetTypeSize (Type t)
1074 t = TypeManager.TypeToCoreType (t);
1075 if (t == TypeManager.int32_type ||
1076 t == TypeManager.uint32_type ||
1077 t == TypeManager.float_type)
1079 else if (t == TypeManager.int64_type ||
1080 t == TypeManager.uint64_type ||
1081 t == TypeManager.double_type)
1083 else if (t == TypeManager.byte_type ||
1084 t == TypeManager.sbyte_type ||
1085 t == TypeManager.bool_type)
1087 else if (t == TypeManager.short_type ||
1088 t == TypeManager.char_type ||
1089 t == TypeManager.ushort_type)
1091 else if (t == TypeManager.decimal_type)
1097 public static void Error_NegativeArrayIndex (Location loc)
1099 Report.Error (248, loc, "Cannot create an array with a negative size");
1102 protected void Error_CannotCallAbstractBase (string name)
1104 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1108 // Converts `source' to an int, uint, long or ulong.
1110 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1114 using (ec.With (EmitContext.Flags.CheckState, true)) {
1115 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1117 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1119 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1121 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1123 if (target == null) {
1124 source.Error_ValueCannotBeConverted (ec, loc, TypeManager.int32_type, false);
1130 // Only positive constants are allowed at compile time
1132 if (target is Constant){
1133 if (target is IntConstant){
1134 if (((IntConstant) target).Value < 0){
1135 Error_NegativeArrayIndex (loc);
1140 if (target is LongConstant){
1141 if (((LongConstant) target).Value < 0){
1142 Error_NegativeArrayIndex (loc);
1155 /// This is just a base class for expressions that can
1156 /// appear on statements (invocations, object creation,
1157 /// assignments, post/pre increment and decrement). The idea
1158 /// being that they would support an extra Emition interface that
1159 /// does not leave a result on the stack.
1161 public abstract class ExpressionStatement : Expression {
1163 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1165 Expression e = Resolve (ec);
1169 ExpressionStatement es = e as ExpressionStatement;
1171 Error_InvalidExpressionStatement ();
1177 /// Requests the expression to be emitted in a `statement'
1178 /// context. This means that no new value is left on the
1179 /// stack after invoking this method (constrasted with
1180 /// Emit that will always leave a value on the stack).
1182 public abstract void EmitStatement (EmitContext ec);
1186 /// This kind of cast is used to encapsulate the child
1187 /// whose type is child.Type into an expression that is
1188 /// reported to return "return_type". This is used to encapsulate
1189 /// expressions which have compatible types, but need to be dealt
1190 /// at higher levels with.
1192 /// For example, a "byte" expression could be encapsulated in one
1193 /// of these as an "unsigned int". The type for the expression
1194 /// would be "unsigned int".
1197 public class EmptyCast : Expression {
1198 protected readonly Expression child;
1200 public EmptyCast (Expression child, Type return_type)
1202 eclass = child.eclass;
1203 loc = child.Location;
1208 public override Expression DoResolve (EmitContext ec)
1210 // This should never be invoked, we are born in fully
1211 // initialized state.
1216 public override void Emit (EmitContext ec)
1221 public override bool GetAttributableValue (Type valueType, out object value)
1223 return child.GetAttributableValue (valueType, out value);
1229 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1231 public class OperatorCast : EmptyCast {
1232 MethodInfo conversion_operator;
1235 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1237 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1238 : base (child, target_type)
1240 this.find_explicit = find_explicit;
1243 // Returns the implicit operator that converts from
1244 // 'child.Type' to our target type (type)
1245 MethodInfo GetConversionOperator (bool find_explicit)
1247 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1251 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1252 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1255 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1256 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1259 foreach (MethodInfo oper in mi) {
1260 ParameterData pd = TypeManager.GetParameterData (oper);
1262 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1270 public override void Emit (EmitContext ec)
1272 ILGenerator ig = ec.ig;
1275 conversion_operator = GetConversionOperator (find_explicit);
1277 if (conversion_operator == null)
1278 throw new InternalErrorException ("Outer conversion routine is out of sync");
1280 ig.Emit (OpCodes.Call, conversion_operator);
1286 /// This is a numeric cast to a Decimal
1288 public class CastToDecimal : EmptyCast {
1289 MethodInfo conversion_operator;
1291 public CastToDecimal (Expression child)
1292 : this (child, false)
1296 public CastToDecimal (Expression child, bool find_explicit)
1297 : base (child, TypeManager.decimal_type)
1299 conversion_operator = GetConversionOperator (find_explicit);
1301 if (conversion_operator == null)
1302 throw new InternalErrorException ("Outer conversion routine is out of sync");
1305 // Returns the implicit operator that converts from
1306 // 'child.Type' to System.Decimal.
1307 MethodInfo GetConversionOperator (bool find_explicit)
1309 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1311 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1312 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1314 foreach (MethodInfo oper in mi) {
1315 ParameterData pd = TypeManager.GetParameterData (oper);
1317 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1323 public override void Emit (EmitContext ec)
1325 ILGenerator ig = ec.ig;
1328 ig.Emit (OpCodes.Call, conversion_operator);
1333 /// This is an explicit numeric cast from a Decimal
1335 public class CastFromDecimal : EmptyCast
1337 static IDictionary operators;
1339 public CastFromDecimal (Expression child, Type return_type)
1340 : base (child, return_type)
1342 if (child.Type != TypeManager.decimal_type)
1343 throw new InternalErrorException (
1344 "The expected type is Decimal, instead it is " + child.Type.FullName);
1347 // Returns the explicit operator that converts from an
1348 // express of type System.Decimal to 'type'.
1349 public Expression Resolve ()
1351 if (operators == null) {
1352 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1353 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1354 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1356 operators = new System.Collections.Specialized.HybridDictionary ();
1357 foreach (MethodInfo oper in all_oper) {
1358 ParameterData pd = TypeManager.GetParameterData (oper);
1359 if (pd.ParameterType (0) == TypeManager.decimal_type)
1360 operators.Add (oper.ReturnType, oper);
1364 return operators.Contains (type) ? this : null;
1367 public override void Emit (EmitContext ec)
1369 ILGenerator ig = ec.ig;
1372 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1378 // Constant specialization of EmptyCast.
1379 // We need to special case this since an empty cast of
1380 // a constant is still a constant.
1382 public class EmptyConstantCast : Constant
1384 public readonly Constant child;
1386 public EmptyConstantCast(Constant child, Type type)
1387 : base (child.Location)
1389 eclass = child.eclass;
1394 public override string AsString ()
1396 return child.AsString ();
1399 public override object GetValue ()
1401 return child.GetValue ();
1404 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1406 // FIXME: check that 'type' can be converted to 'target_type' first
1407 return child.ConvertExplicitly (inCheckedContext, target_type);
1410 public override Constant Increment ()
1412 return child.Increment ();
1415 public override bool IsDefaultValue {
1416 get { return child.IsDefaultValue; }
1419 public override bool IsNegative {
1420 get { return child.IsNegative; }
1423 public override void Emit (EmitContext ec)
1428 public override Constant ConvertImplicitly (Type target_type)
1430 // FIXME: Do we need to check user conversions?
1431 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1433 return child.ConvertImplicitly (target_type);
1439 /// This class is used to wrap literals which belong inside Enums
1441 public class EnumConstant : Constant {
1442 public Constant Child;
1444 public EnumConstant (Constant child, Type enum_type):
1445 base (child.Location)
1447 eclass = child.eclass;
1452 public override Expression DoResolve (EmitContext ec)
1454 // This should never be invoked, we are born in fully
1455 // initialized state.
1460 public override void Emit (EmitContext ec)
1465 public override bool GetAttributableValue (Type valueType, out object value)
1467 value = GetTypedValue ();
1471 public override string GetSignatureForError()
1473 return TypeManager.CSharpName (Type);
1476 public override object GetValue ()
1478 return Child.GetValue ();
1481 public override object GetTypedValue ()
1483 // FIXME: runtime is not ready to work with just emited enums
1484 if (!RootContext.StdLib) {
1485 return Child.GetValue ();
1488 return System.Enum.ToObject (type, Child.GetValue ());
1491 public override string AsString ()
1493 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1496 public override Constant Increment()
1498 return new EnumConstant (Child.Increment (), type);
1501 public override bool IsDefaultValue {
1503 return Child.IsDefaultValue;
1507 public override bool IsZeroInteger {
1508 get { return Child.IsZeroInteger; }
1511 public override bool IsNegative {
1513 return Child.IsNegative;
1517 public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type)
1519 if (Child.Type == target_type)
1522 return Child.ConvertExplicitly (inCheckedContext, target_type);
1525 public override Constant ConvertImplicitly (Type type)
1528 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1529 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1532 if (type.UnderlyingSystemType != Child.Type)
1533 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1537 if (!Convert.ImplicitStandardConversionExists (this, type)){
1541 return Child.ConvertImplicitly(type);
1547 /// This kind of cast is used to encapsulate Value Types in objects.
1549 /// The effect of it is to box the value type emitted by the previous
1552 public class BoxedCast : EmptyCast {
1554 public BoxedCast (Expression expr, Type target_type)
1555 : base (expr, target_type)
1557 eclass = ExprClass.Value;
1560 public override Expression DoResolve (EmitContext ec)
1562 // This should never be invoked, we are born in fully
1563 // initialized state.
1568 public override void Emit (EmitContext ec)
1572 ec.ig.Emit (OpCodes.Box, child.Type);
1576 public class UnboxCast : EmptyCast {
1577 public UnboxCast (Expression expr, Type return_type)
1578 : base (expr, return_type)
1582 public override Expression DoResolve (EmitContext ec)
1584 // This should never be invoked, we are born in fully
1585 // initialized state.
1590 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1592 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1593 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1594 return base.DoResolveLValue (ec, right_side);
1597 public override void Emit (EmitContext ec)
1600 ILGenerator ig = ec.ig;
1604 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1605 ig.Emit (OpCodes.Unbox_Any, t);
1609 ig.Emit (OpCodes.Unbox, t);
1611 LoadFromPtr (ig, t);
1617 /// This is used to perform explicit numeric conversions.
1619 /// Explicit numeric conversions might trigger exceptions in a checked
1620 /// context, so they should generate the conv.ovf opcodes instead of
1623 public class ConvCast : EmptyCast {
1624 public enum Mode : byte {
1625 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1627 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1628 U2_I1, U2_U1, U2_I2, U2_CH,
1629 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1630 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1631 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1632 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1633 CH_I1, CH_U1, CH_I2,
1634 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1635 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1640 public ConvCast (Expression child, Type return_type, Mode m)
1641 : base (child, return_type)
1646 public override Expression DoResolve (EmitContext ec)
1648 // This should never be invoked, we are born in fully
1649 // initialized state.
1654 public override string ToString ()
1656 return String.Format ("ConvCast ({0}, {1})", mode, child);
1659 public override void Emit (EmitContext ec)
1661 ILGenerator ig = ec.ig;
1667 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1668 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1669 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1670 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1671 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1673 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1674 case Mode.U1_CH: /* nothing */ break;
1676 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1677 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1678 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1679 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1680 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1681 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1683 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1684 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1685 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1686 case Mode.U2_CH: /* nothing */ break;
1688 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1689 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1690 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1691 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1692 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1693 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1694 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1696 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1697 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1698 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1699 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1700 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1701 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1703 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1704 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1705 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1706 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1707 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1708 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1709 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1710 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1712 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1713 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1714 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1715 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1716 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1717 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1718 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1719 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1721 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1722 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1723 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1725 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1726 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1727 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1728 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1729 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1730 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1731 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1732 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1733 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1735 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1736 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1737 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1738 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1739 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1740 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1741 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1742 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1743 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1744 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1748 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1749 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1750 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1751 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1752 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1754 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1755 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1757 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1758 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1759 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1760 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1761 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1762 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1764 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1765 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1766 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1767 case Mode.U2_CH: /* nothing */ break;
1769 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1770 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1771 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1772 case Mode.I4_U4: /* nothing */ break;
1773 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1774 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1775 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1777 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1778 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1779 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1780 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1781 case Mode.U4_I4: /* nothing */ break;
1782 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1784 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1785 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1786 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1787 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1788 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1789 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1790 case Mode.I8_U8: /* nothing */ break;
1791 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1793 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1794 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1795 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1796 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1797 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1798 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1799 case Mode.U8_I8: /* nothing */ break;
1800 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1802 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1803 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1804 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1806 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1807 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1808 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1809 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1810 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1811 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1812 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1813 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1814 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1816 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1817 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1818 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1819 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1820 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1821 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1822 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1823 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1824 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1825 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1831 public class OpcodeCast : EmptyCast {
1835 public OpcodeCast (Expression child, Type return_type, OpCode op)
1836 : base (child, return_type)
1840 second_valid = false;
1843 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1844 : base (child, return_type)
1849 second_valid = true;
1852 public override Expression DoResolve (EmitContext ec)
1854 // This should never be invoked, we are born in fully
1855 // initialized state.
1860 public override void Emit (EmitContext ec)
1871 /// This kind of cast is used to encapsulate a child and cast it
1872 /// to the class requested
1874 public class ClassCast : EmptyCast {
1875 public ClassCast (Expression child, Type return_type)
1876 : base (child, return_type)
1881 public override Expression DoResolve (EmitContext ec)
1883 // This should never be invoked, we are born in fully
1884 // initialized state.
1889 public override void Emit (EmitContext ec)
1893 if (TypeManager.IsGenericParameter (child.Type))
1894 ec.ig.Emit (OpCodes.Box, child.Type);
1897 if (type.IsGenericParameter)
1898 ec.ig.Emit (OpCodes.Unbox_Any, type);
1901 ec.ig.Emit (OpCodes.Castclass, type);
1906 /// SimpleName expressions are formed of a single word and only happen at the beginning
1907 /// of a dotted-name.
1909 public class SimpleName : Expression {
1911 public readonly TypeArguments Arguments;
1914 public SimpleName (string name, Location l)
1920 public SimpleName (string name, TypeArguments args, Location l)
1927 public SimpleName (string name, TypeParameter[] type_params, Location l)
1932 Arguments = new TypeArguments (l);
1933 foreach (TypeParameter type_param in type_params)
1934 Arguments.Add (new TypeParameterExpr (type_param, l));
1937 public static string RemoveGenericArity (string name)
1940 StringBuilder sb = null;
1942 int pos = name.IndexOf ('`', start);
1947 sb.Append (name.Substring (start));
1952 sb = new StringBuilder ();
1953 sb.Append (name.Substring (start, pos-start));
1956 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1960 } while (start < name.Length);
1962 return sb.ToString ();
1965 public SimpleName GetMethodGroup ()
1967 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1970 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1972 if (ec.IsFieldInitializer)
1973 Report.Error (236, l,
1974 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1978 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1982 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1984 return resolved_to != null && resolved_to.Type != null &&
1985 resolved_to.Type.Name == Name &&
1986 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
1989 public override Expression DoResolve (EmitContext ec)
1991 return SimpleNameResolve (ec, null, false);
1994 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1996 return SimpleNameResolve (ec, right_side, false);
2000 public Expression DoResolve (EmitContext ec, bool intermediate)
2002 return SimpleNameResolve (ec, null, intermediate);
2005 private bool IsNestedChild (Type t, Type parent)
2010 while (parent != null) {
2011 parent = TypeManager.DropGenericTypeArguments (parent);
2012 if (TypeManager.IsNestedChildOf (t, parent))
2015 parent = parent.BaseType;
2021 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2023 if (!TypeManager.IsGenericTypeDefinition (t))
2026 DeclSpace ds = ec.DeclContainer;
2027 while (ds != null) {
2028 if (IsNestedChild (t, ds.TypeBuilder))
2037 Type[] gen_params = TypeManager.GetTypeArguments (t);
2039 int arg_count = Arguments != null ? Arguments.Count : 0;
2041 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2042 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2043 TypeArguments new_args = new TypeArguments (loc);
2044 foreach (TypeParameter param in ds.TypeParameters)
2045 new_args.Add (new TypeParameterExpr (param, loc));
2047 if (Arguments != null)
2048 new_args.Add (Arguments);
2050 return new ConstructedType (t, new_args, loc);
2057 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2059 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2061 return fne.ResolveAsTypeStep (ec, silent);
2063 int errors = Report.Errors;
2064 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2067 if (fne.Type == null)
2070 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2072 return nested.ResolveAsTypeStep (ec, false);
2074 if (Arguments != null) {
2075 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2076 return ct.ResolveAsTypeStep (ec, false);
2082 if (silent || errors != Report.Errors)
2085 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2087 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2091 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2092 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2093 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2094 Type type = a.GetType (fullname);
2096 Report.SymbolRelatedToPreviousError (type);
2097 Expression.ErrorIsInaccesible (loc, fullname);
2102 Type t = ec.DeclContainer.NamespaceEntry.NS.LookForAnyGenericType (Name);
2104 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2108 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2112 // TODO: I am still not convinced about this. If someone else will need it
2113 // implement this as virtual property in MemberCore hierarchy
2114 public static string GetMemberType (MemberCore mc)
2120 if (mc is FieldBase)
2122 if (mc is MethodCore)
2124 if (mc is EnumMember)
2132 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2138 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2142 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2149 /// 7.5.2: Simple Names.
2151 /// Local Variables and Parameters are handled at
2152 /// parse time, so they never occur as SimpleNames.
2154 /// The `intermediate' flag is used by MemberAccess only
2155 /// and it is used to inform us that it is ok for us to
2156 /// avoid the static check, because MemberAccess might end
2157 /// up resolving the Name as a Type name and the access as
2158 /// a static type access.
2160 /// ie: Type Type; .... { Type.GetType (""); }
2162 /// Type is both an instance variable and a Type; Type.GetType
2163 /// is the static method not an instance method of type.
2165 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2167 Expression e = null;
2170 // Stage 1: Performed by the parser (binding to locals or parameters).
2172 Block current_block = ec.CurrentBlock;
2173 if (current_block != null){
2174 LocalInfo vi = current_block.GetLocalInfo (Name);
2176 if (Arguments != null) {
2177 Report.Error (307, loc,
2178 "The variable `{0}' cannot be used with type arguments",
2183 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2184 if (right_side != null) {
2185 return var.ResolveLValue (ec, right_side, loc);
2187 ResolveFlags rf = ResolveFlags.VariableOrValue;
2189 rf |= ResolveFlags.DisableFlowAnalysis;
2190 return var.Resolve (ec, rf);
2194 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2196 if (Arguments != null) {
2197 Report.Error (307, loc,
2198 "The variable `{0}' cannot be used with type arguments",
2203 if (right_side != null)
2204 return pref.ResolveLValue (ec, right_side, loc);
2206 return pref.Resolve (ec);
2211 // Stage 2: Lookup members
2214 DeclSpace lookup_ds = ec.DeclContainer;
2215 Type almost_matched_type = null;
2216 ArrayList almost_matched = null;
2218 if (lookup_ds.TypeBuilder == null)
2221 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2225 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2226 almost_matched_type = lookup_ds.TypeBuilder;
2227 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2230 lookup_ds =lookup_ds.Parent;
2231 } while (lookup_ds != null);
2233 if (e == null && ec.ContainerType != null)
2234 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2237 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2238 almost_matched_type = ec.ContainerType;
2239 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2241 e = ResolveAsTypeStep (ec, true);
2245 if (almost_matched != null)
2246 almostMatchedMembers = almost_matched;
2247 if (almost_matched_type == null)
2248 almost_matched_type = ec.ContainerType;
2249 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2253 if (e is TypeExpr) {
2254 if (Arguments == null)
2257 ConstructedType ct = new ConstructedType (
2258 (FullNamedExpression) e, Arguments, loc);
2259 return ct.ResolveAsTypeStep (ec, false);
2262 if (e is MemberExpr) {
2263 MemberExpr me = (MemberExpr) e;
2266 if (me.IsInstance) {
2267 if (ec.IsStatic || ec.IsFieldInitializer) {
2269 // Note that an MemberExpr can be both IsInstance and IsStatic.
2270 // An unresolved MethodGroupExpr can contain both kinds of methods
2271 // and each predicate is true if the MethodGroupExpr contains
2272 // at least one of that kind of method.
2276 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2277 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2278 return EmptyExpression.Null;
2282 // Pass the buck to MemberAccess and Invocation.
2284 left = EmptyExpression.Null;
2286 left = ec.GetThis (loc);
2289 left = new TypeExpression (ec.ContainerType, loc);
2292 e = me.ResolveMemberAccess (ec, left, loc, null);
2296 me = e as MemberExpr;
2300 if (Arguments != null) {
2301 MethodGroupExpr mg = me as MethodGroupExpr;
2305 return mg.ResolveGeneric (ec, Arguments);
2308 if (!me.IsStatic && (me.InstanceExpression != null) &&
2309 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2310 me.InstanceExpression.Type != me.DeclaringType &&
2311 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2312 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2313 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2314 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2318 return (right_side != null)
2319 ? me.DoResolveLValue (ec, right_side)
2320 : me.DoResolve (ec);
2326 public override void Emit (EmitContext ec)
2329 // If this is ever reached, then we failed to
2330 // find the name as a namespace
2333 Error (103, "The name `" + Name +
2334 "' does not exist in the class `" +
2335 ec.DeclContainer.Name + "'");
2338 public override string ToString ()
2343 public override string GetSignatureForError ()
2350 /// Represents a namespace or a type. The name of the class was inspired by
2351 /// section 10.8.1 (Fully Qualified Names).
2353 public abstract class FullNamedExpression : Expression {
2354 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2359 public abstract string FullName {
2365 /// Expression that evaluates to a type
2367 public abstract class TypeExpr : FullNamedExpression {
2368 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2370 TypeExpr t = DoResolveAsTypeStep (ec);
2374 eclass = ExprClass.Type;
2378 override public Expression DoResolve (EmitContext ec)
2380 return ResolveAsTypeTerminal (ec, false);
2383 override public void Emit (EmitContext ec)
2385 throw new Exception ("Should never be called");
2388 public virtual bool CheckAccessLevel (DeclSpace ds)
2390 return ds.CheckAccessLevel (Type);
2393 public virtual bool AsAccessible (DeclSpace ds, int flags)
2395 return ds.AsAccessible (Type, flags);
2398 public virtual bool IsClass {
2399 get { return Type.IsClass; }
2402 public virtual bool IsValueType {
2403 get { return Type.IsValueType; }
2406 public virtual bool IsInterface {
2407 get { return Type.IsInterface; }
2410 public virtual bool IsSealed {
2411 get { return Type.IsSealed; }
2414 public virtual bool CanInheritFrom ()
2416 if (Type == TypeManager.enum_type ||
2417 (Type == TypeManager.value_type && RootContext.StdLib) ||
2418 Type == TypeManager.multicast_delegate_type ||
2419 Type == TypeManager.delegate_type ||
2420 Type == TypeManager.array_type)
2426 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2428 public abstract string Name {
2432 public override bool Equals (object obj)
2434 TypeExpr tobj = obj as TypeExpr;
2438 return Type == tobj.Type;
2441 public override int GetHashCode ()
2443 return Type.GetHashCode ();
2446 public override string ToString ()
2453 /// Fully resolved Expression that already evaluated to a type
2455 public class TypeExpression : TypeExpr {
2456 public TypeExpression (Type t, Location l)
2459 eclass = ExprClass.Type;
2463 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2468 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2473 public override string Name {
2474 get { return Type.ToString (); }
2477 public override string FullName {
2478 get { return Type.FullName; }
2483 /// Used to create types from a fully qualified name. These are just used
2484 /// by the parser to setup the core types. A TypeLookupExpression is always
2485 /// classified as a type.
2487 public sealed class TypeLookupExpression : TypeExpr {
2488 readonly string name;
2490 public TypeLookupExpression (string name)
2493 eclass = ExprClass.Type;
2496 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2498 // It's null for corlib compilation only
2500 return DoResolveAsTypeStep (ec);
2505 static readonly char [] dot_array = { '.' };
2506 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2508 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2510 string lookup_name = name;
2511 int pos = name.IndexOf ('.');
2513 rest = name.Substring (pos + 1);
2514 lookup_name = name.Substring (0, pos);
2517 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2519 if (resolved != null && rest != null) {
2520 // Now handle the rest of the the name.
2521 string [] elements = rest.Split (dot_array);
2523 int count = elements.Length;
2525 while (i < count && resolved != null && resolved is Namespace) {
2526 Namespace ns = resolved as Namespace;
2527 element = elements [i++];
2528 lookup_name += "." + element;
2529 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2532 if (resolved != null && resolved is TypeExpr) {
2533 Type t = ((TypeExpr) resolved).Type;
2535 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2537 lookup_name = t.FullName;
2544 t = TypeManager.GetNestedType (t, elements [i++]);
2549 if (resolved == null) {
2550 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2554 if (!(resolved is TypeExpr)) {
2555 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2559 type = resolved.Type;
2563 public override string Name {
2564 get { return name; }
2567 public override string FullName {
2568 get { return name; }
2573 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2576 public class UnboundTypeExpression : TypeExpr
2580 public UnboundTypeExpression (MemberName name, Location l)
2586 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2589 if (name.Left != null) {
2590 Expression lexpr = name.Left.GetTypeExpression ();
2591 expr = new MemberAccess (lexpr, name.Basename);
2593 expr = new SimpleName (name.Basename, loc);
2596 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2601 return new TypeExpression (type, loc);
2604 public override string Name {
2605 get { return name.FullName; }
2608 public override string FullName {
2609 get { return name.FullName; }
2613 public class TypeAliasExpression : TypeExpr {
2614 FullNamedExpression alias;
2619 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2625 eclass = ExprClass.Type;
2627 name = alias.FullName + "<" + args.ToString () + ">";
2629 name = alias.FullName;
2632 public override string Name {
2633 get { return alias.FullName; }
2636 public override string FullName {
2637 get { return name; }
2640 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2642 texpr = alias.ResolveAsTypeTerminal (ec, false);
2646 Type type = texpr.Type;
2647 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2650 if (num_args == 0) {
2651 Report.Error (308, loc,
2652 "The non-generic type `{0}' cannot " +
2653 "be used with type arguments.",
2654 TypeManager.CSharpName (type));
2658 ConstructedType ctype = new ConstructedType (type, args, loc);
2659 return ctype.ResolveAsTypeTerminal (ec, false);
2660 } else if (num_args > 0) {
2661 Report.Error (305, loc,
2662 "Using the generic type `{0}' " +
2663 "requires {1} type arguments",
2664 TypeManager.CSharpName (type), num_args.ToString ());
2671 public override bool CheckAccessLevel (DeclSpace ds)
2673 return texpr.CheckAccessLevel (ds);
2676 public override bool AsAccessible (DeclSpace ds, int flags)
2678 return texpr.AsAccessible (ds, flags);
2681 public override bool IsClass {
2682 get { return texpr.IsClass; }
2685 public override bool IsValueType {
2686 get { return texpr.IsValueType; }
2689 public override bool IsInterface {
2690 get { return texpr.IsInterface; }
2693 public override bool IsSealed {
2694 get { return texpr.IsSealed; }
2699 /// This class denotes an expression which evaluates to a member
2700 /// of a struct or a class.
2702 public abstract class MemberExpr : Expression
2705 /// The name of this member.
2707 public abstract string Name {
2712 /// Whether this is an instance member.
2714 public abstract bool IsInstance {
2719 /// Whether this is a static member.
2721 public abstract bool IsStatic {
2726 /// The type which declares this member.
2728 public abstract Type DeclaringType {
2733 /// The instance expression associated with this member, if it's a
2734 /// non-static member.
2736 public Expression InstanceExpression;
2738 public static void error176 (Location loc, string name)
2740 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2741 "with an instance reference, qualify it with a type name instead", name);
2744 // TODO: possible optimalization
2745 // Cache resolved constant result in FieldBuilder <-> expression map
2746 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2747 SimpleName original)
2751 // original == null || original.Resolve (...) ==> left
2754 if (left is TypeExpr) {
2756 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2764 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2767 error176 (loc, GetSignatureForError ());
2771 InstanceExpression = left;
2776 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2781 if (InstanceExpression == EmptyExpression.Null) {
2782 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2786 if (InstanceExpression.Type.IsValueType) {
2787 if (InstanceExpression is IMemoryLocation) {
2788 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2790 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2791 InstanceExpression.Emit (ec);
2793 t.AddressOf (ec, AddressOp.Store);
2796 InstanceExpression.Emit (ec);
2798 if (prepare_for_load)
2799 ec.ig.Emit (OpCodes.Dup);
2804 /// MethodGroup Expression.
2806 /// This is a fully resolved expression that evaluates to a type
2808 public class MethodGroupExpr : MemberExpr {
2809 public MethodBase [] Methods;
2810 bool has_type_arguments = false;
2811 bool identical_type_name = false;
2814 public MethodGroupExpr (MemberInfo [] mi, Location l)
2816 Methods = new MethodBase [mi.Length];
2817 mi.CopyTo (Methods, 0);
2818 eclass = ExprClass.MethodGroup;
2820 // Set the type to something that will never be useful, which will
2821 // trigger the proper conversions.
2822 type = typeof (MethodGroupExpr);
2826 public MethodGroupExpr (ArrayList list, Location l)
2828 Methods = new MethodBase [list.Count];
2831 list.CopyTo (Methods, 0);
2833 foreach (MemberInfo m in list){
2834 if (!(m is MethodBase)){
2835 Console.WriteLine ("Name " + m.Name);
2836 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2843 eclass = ExprClass.MethodGroup;
2844 type = TypeManager.object_type;
2847 public override Type DeclaringType {
2850 // We assume that the top-level type is in the end
2852 return Methods [Methods.Length - 1].DeclaringType;
2853 //return Methods [0].DeclaringType;
2857 public bool HasTypeArguments {
2859 return has_type_arguments;
2863 has_type_arguments = value;
2867 public bool IdenticalTypeName {
2869 return identical_type_name;
2873 identical_type_name = value;
2877 public bool IsBase {
2886 public override string GetSignatureForError ()
2888 return TypeManager.CSharpSignature (Methods [0]);
2891 public override string Name {
2893 return Methods [0].Name;
2897 public override bool IsInstance {
2899 foreach (MethodBase mb in Methods)
2907 public override bool IsStatic {
2909 foreach (MethodBase mb in Methods)
2917 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2918 SimpleName original)
2920 if (!(left is TypeExpr) &&
2921 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2922 IdenticalTypeName = true;
2924 return base.ResolveMemberAccess (ec, left, loc, original);
2927 override public Expression DoResolve (EmitContext ec)
2930 InstanceExpression = null;
2932 if (InstanceExpression != null) {
2933 InstanceExpression = InstanceExpression.DoResolve (ec);
2934 if (InstanceExpression == null)
2941 public void ReportUsageError ()
2943 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2944 Name + "()' is referenced without parentheses");
2947 override public void Emit (EmitContext ec)
2949 ReportUsageError ();
2952 bool RemoveMethods (bool keep_static)
2954 ArrayList smethods = new ArrayList ();
2956 foreach (MethodBase mb in Methods){
2957 if (mb.IsStatic == keep_static)
2961 if (smethods.Count == 0)
2964 Methods = new MethodBase [smethods.Count];
2965 smethods.CopyTo (Methods, 0);
2971 /// Removes any instance methods from the MethodGroup, returns
2972 /// false if the resulting set is empty.
2974 public bool RemoveInstanceMethods ()
2976 return RemoveMethods (true);
2980 /// Removes any static methods from the MethodGroup, returns
2981 /// false if the resulting set is empty.
2983 public bool RemoveStaticMethods ()
2985 return RemoveMethods (false);
2988 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2991 if (args.Resolve (ec) == false)
2994 Type[] atypes = args.Arguments;
2996 int first_count = 0;
2997 MethodInfo first = null;
2999 ArrayList list = new ArrayList ();
3000 foreach (MethodBase mb in Methods) {
3001 MethodInfo mi = mb as MethodInfo;
3002 if ((mi == null) || !mi.IsGenericMethod)
3005 Type[] gen_params = mi.GetGenericArguments ();
3007 if (first == null) {
3009 first_count = gen_params.Length;
3012 if (gen_params.Length != atypes.Length)
3015 list.Add (mi.MakeGenericMethod (atypes));
3018 if (list.Count > 0) {
3019 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3020 new_mg.InstanceExpression = InstanceExpression;
3021 new_mg.HasTypeArguments = true;
3022 new_mg.IsBase = IsBase;
3028 305, loc, "Using the generic method `{0}' " +
3029 "requires {1} type arguments", Name,
3030 first_count.ToString ());
3033 308, loc, "The non-generic method `{0}' " +
3034 "cannot be used with type arguments", Name);
3038 throw new NotImplementedException ();
3044 /// Fully resolved expression that evaluates to a Field
3046 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3047 public readonly FieldInfo FieldInfo;
3048 VariableInfo variable_info;
3050 LocalTemporary temp;
3052 bool in_initializer;
3054 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3057 this.in_initializer = in_initializer;
3060 public FieldExpr (FieldInfo fi, Location l)
3063 eclass = ExprClass.Variable;
3064 type = TypeManager.TypeToCoreType (fi.FieldType);
3068 public override string Name {
3070 return FieldInfo.Name;
3074 public override bool IsInstance {
3076 return !FieldInfo.IsStatic;
3080 public override bool IsStatic {
3082 return FieldInfo.IsStatic;
3086 public override Type DeclaringType {
3088 return FieldInfo.DeclaringType;
3092 public override string GetSignatureForError ()
3094 return TypeManager.GetFullNameSignature (FieldInfo);
3097 public VariableInfo VariableInfo {
3099 return variable_info;
3103 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3104 SimpleName original)
3106 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3108 Type t = fi.FieldType;
3110 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3111 IConstant ic = TypeManager.GetConstant (fi);
3114 ic = new ExternalConstant (fi);
3116 ic = ExternalConstant.CreateDecimal (fi);
3118 return base.ResolveMemberAccess (ec, left, loc, original);
3121 TypeManager.RegisterConstant (fi, ic);
3124 bool left_is_type = left is TypeExpr;
3125 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3126 Report.SymbolRelatedToPreviousError (FieldInfo);
3127 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3131 if (ic.ResolveValue ()) {
3132 if (!ec.IsInObsoleteScope)
3133 ic.CheckObsoleteness (loc);
3136 return ic.CreateConstantReference (loc);
3139 if (t.IsPointer && !ec.InUnsafe) {
3144 return base.ResolveMemberAccess (ec, left, loc, original);
3147 override public Expression DoResolve (EmitContext ec)
3149 return DoResolve (ec, false, false);
3152 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3154 if (!FieldInfo.IsStatic){
3155 if (InstanceExpression == null){
3157 // This can happen when referencing an instance field using
3158 // a fully qualified type expression: TypeName.InstanceField = xxx
3160 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3164 // Resolve the field's instance expression while flow analysis is turned
3165 // off: when accessing a field "a.b", we must check whether the field
3166 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3168 if (lvalue_instance) {
3169 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3170 Expression right_side =
3171 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3172 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3175 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3176 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3179 if (InstanceExpression == null)
3182 InstanceExpression.CheckMarshalByRefAccess ();
3185 if (!in_initializer && !ec.IsFieldInitializer) {
3186 ObsoleteAttribute oa;
3187 FieldBase f = TypeManager.GetField (FieldInfo);
3189 if (!ec.IsInObsoleteScope)
3190 f.CheckObsoleteness (loc);
3192 // To be sure that type is external because we do not register generated fields
3193 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3194 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3196 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3200 AnonymousContainer am = ec.CurrentAnonymousMethod;
3202 if (!FieldInfo.IsStatic){
3203 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3204 Report.Error (1673, loc,
3205 "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",
3212 // If the instance expression is a local variable or parameter.
3213 IVariable var = InstanceExpression as IVariable;
3214 if ((var == null) || (var.VariableInfo == null))
3217 VariableInfo vi = var.VariableInfo;
3218 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3221 variable_info = vi.GetSubStruct (FieldInfo.Name);
3225 static readonly int [] codes = {
3226 191, // instance, write access
3227 192, // instance, out access
3228 198, // static, write access
3229 199, // static, out access
3230 1648, // member of value instance, write access
3231 1649, // member of value instance, out access
3232 1650, // member of value static, write access
3233 1651 // member of value static, out access
3236 static readonly string [] msgs = {
3237 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3238 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3239 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3240 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3241 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3242 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3243 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3244 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3247 // The return value is always null. Returning a value simplifies calling code.
3248 Expression Report_AssignToReadonly (Expression right_side)
3251 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3255 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3257 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3262 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3264 IVariable var = InstanceExpression as IVariable;
3265 if ((var != null) && (var.VariableInfo != null))
3266 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3268 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3269 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3271 Expression e = DoResolve (ec, lvalue_instance, out_access);
3276 FieldBase fb = TypeManager.GetField (FieldInfo);
3280 if (FieldInfo.IsInitOnly) {
3281 // InitOnly fields can only be assigned in constructors or initializers
3282 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3283 return Report_AssignToReadonly (right_side);
3285 if (ec.IsConstructor) {
3286 Type ctype = ec.TypeContainer.CurrentType;
3288 ctype = ec.ContainerType;
3290 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3291 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3292 return Report_AssignToReadonly (right_side);
3293 // static InitOnly fields cannot be assigned-to in an instance constructor
3294 if (IsStatic && !ec.IsStatic)
3295 return Report_AssignToReadonly (right_side);
3296 // instance constructors can't modify InitOnly fields of other instances of the same type
3297 if (!IsStatic && !(InstanceExpression is This))
3298 return Report_AssignToReadonly (right_side);
3302 if (right_side == EmptyExpression.OutAccess &&
3303 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3304 Report.SymbolRelatedToPreviousError (DeclaringType);
3305 Report.Warning (197, 1, loc,
3306 "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",
3307 GetSignatureForError ());
3313 public override void CheckMarshalByRefAccess ()
3315 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3316 Report.SymbolRelatedToPreviousError (DeclaringType);
3317 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",
3318 GetSignatureForError ());
3322 public bool VerifyFixed ()
3324 IVariable variable = InstanceExpression as IVariable;
3325 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3326 // We defer the InstanceExpression check after the variable check to avoid a
3327 // separate null check on InstanceExpression.
3328 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3331 public override int GetHashCode ()
3333 return FieldInfo.GetHashCode ();
3336 public override bool Equals (object obj)
3338 FieldExpr fe = obj as FieldExpr;
3342 if (FieldInfo != fe.FieldInfo)
3345 if (InstanceExpression == null || fe.InstanceExpression == null)
3348 return InstanceExpression.Equals (fe.InstanceExpression);
3351 public void Emit (EmitContext ec, bool leave_copy)
3353 ILGenerator ig = ec.ig;
3354 bool is_volatile = false;
3356 FieldBase f = TypeManager.GetField (FieldInfo);
3358 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3361 f.SetMemberIsUsed ();
3364 if (FieldInfo.IsStatic){
3366 ig.Emit (OpCodes.Volatile);
3368 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3371 EmitInstance (ec, false);
3374 ig.Emit (OpCodes.Volatile);
3376 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3379 ig.Emit (OpCodes.Ldflda, FieldInfo);
3380 ig.Emit (OpCodes.Ldflda, ff.Element);
3383 ig.Emit (OpCodes.Ldfld, FieldInfo);
3388 ec.ig.Emit (OpCodes.Dup);
3389 if (!FieldInfo.IsStatic) {
3390 temp = new LocalTemporary (this.Type);
3396 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3398 FieldAttributes fa = FieldInfo.Attributes;
3399 bool is_static = (fa & FieldAttributes.Static) != 0;
3400 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3401 ILGenerator ig = ec.ig;
3402 prepared = prepare_for_load;
3404 if (is_readonly && !ec.IsConstructor){
3405 Report_AssignToReadonly (source);
3409 EmitInstance (ec, prepare_for_load);
3413 ec.ig.Emit (OpCodes.Dup);
3414 if (!FieldInfo.IsStatic) {
3415 temp = new LocalTemporary (this.Type);
3420 FieldBase f = TypeManager.GetField (FieldInfo);
3422 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3423 ig.Emit (OpCodes.Volatile);
3429 ig.Emit (OpCodes.Stsfld, FieldInfo);
3431 ig.Emit (OpCodes.Stfld, FieldInfo);
3439 public override void Emit (EmitContext ec)
3444 public void AddressOf (EmitContext ec, AddressOp mode)
3446 ILGenerator ig = ec.ig;
3448 FieldBase f = TypeManager.GetField (FieldInfo);
3450 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3451 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3452 f.GetSignatureForError ());
3456 if ((mode & AddressOp.Store) != 0)
3458 if ((mode & AddressOp.Load) != 0)
3459 f.SetMemberIsUsed ();
3463 // Handle initonly fields specially: make a copy and then
3464 // get the address of the copy.
3467 if (FieldInfo.IsInitOnly){
3469 if (ec.IsConstructor){
3470 if (FieldInfo.IsStatic){
3482 local = ig.DeclareLocal (type);
3483 ig.Emit (OpCodes.Stloc, local);
3484 ig.Emit (OpCodes.Ldloca, local);
3489 if (FieldInfo.IsStatic){
3490 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3493 EmitInstance (ec, false);
3494 ig.Emit (OpCodes.Ldflda, FieldInfo);
3500 // A FieldExpr whose address can not be taken
3502 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3503 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3507 public new void AddressOf (EmitContext ec, AddressOp mode)
3509 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3514 /// Expression that evaluates to a Property. The Assign class
3515 /// might set the `Value' expression if we are in an assignment.
3517 /// This is not an LValue because we need to re-write the expression, we
3518 /// can not take data from the stack and store it.
3520 public class PropertyExpr : MemberExpr, IAssignMethod {
3521 public readonly PropertyInfo PropertyInfo;
3524 // This is set externally by the `BaseAccess' class
3527 MethodInfo getter, setter;
3532 LocalTemporary temp;
3535 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3538 eclass = ExprClass.PropertyAccess;
3542 type = TypeManager.TypeToCoreType (pi.PropertyType);
3544 ResolveAccessors (containerType);
3547 public override string Name {
3549 return PropertyInfo.Name;
3553 public override bool IsInstance {
3559 public override bool IsStatic {
3565 public override Type DeclaringType {
3567 return PropertyInfo.DeclaringType;
3571 public override string GetSignatureForError ()
3573 return TypeManager.GetFullNameSignature (PropertyInfo);
3576 void FindAccessors (Type invocation_type)
3578 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3579 BindingFlags.Static | BindingFlags.Instance |
3580 BindingFlags.DeclaredOnly;
3582 Type current = PropertyInfo.DeclaringType;
3583 for (; current != null; current = current.BaseType) {
3584 MemberInfo[] group = TypeManager.MemberLookup (
3585 invocation_type, invocation_type, current,
3586 MemberTypes.Property, flags, PropertyInfo.Name, null);
3591 if (group.Length != 1)
3592 // Oooops, can this ever happen ?
3595 PropertyInfo pi = (PropertyInfo) group [0];
3598 getter = pi.GetGetMethod (true);
3601 setter = pi.GetSetMethod (true);
3603 MethodInfo accessor = getter != null ? getter : setter;
3605 if (!accessor.IsVirtual)
3611 // We also perform the permission checking here, as the PropertyInfo does not
3612 // hold the information for the accessibility of its setter/getter
3614 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
3615 void ResolveAccessors (Type containerType)
3617 FindAccessors (containerType);
3619 if (getter != null) {
3620 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3621 IMethodData md = TypeManager.GetMethod (the_getter);
3623 md.SetMemberIsUsed ();
3625 is_static = getter.IsStatic;
3628 if (setter != null) {
3629 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3630 IMethodData md = TypeManager.GetMethod (the_setter);
3632 md.SetMemberIsUsed ();
3634 is_static = setter.IsStatic;
3638 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3641 InstanceExpression = null;
3645 if (InstanceExpression == null) {
3646 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3650 InstanceExpression = InstanceExpression.DoResolve (ec);
3651 if (lvalue_instance && InstanceExpression != null)
3652 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3654 if (InstanceExpression == null)
3657 InstanceExpression.CheckMarshalByRefAccess ();
3659 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
3660 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
3661 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
3662 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
3663 Report.SymbolRelatedToPreviousError (PropertyInfo);
3664 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3671 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3673 // TODO: correctly we should compare arguments but it will lead to bigger changes
3674 if (mi is MethodBuilder) {
3675 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3679 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3681 ParameterData iparams = TypeManager.GetParameterData (mi);
3682 sig.Append (getter ? "get_" : "set_");
3684 sig.Append (iparams.GetSignatureForError ());
3686 Report.SymbolRelatedToPreviousError (mi);
3687 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3688 Name, sig.ToString ());
3691 override public Expression DoResolve (EmitContext ec)
3696 if (getter != null){
3697 if (TypeManager.GetParameterData (getter).Count != 0){
3698 Error_PropertyNotFound (getter, true);
3703 if (getter == null){
3705 // The following condition happens if the PropertyExpr was
3706 // created, but is invalid (ie, the property is inaccessible),
3707 // and we did not want to embed the knowledge about this in
3708 // the caller routine. This only avoids double error reporting.
3713 if (InstanceExpression != EmptyExpression.Null) {
3714 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3715 TypeManager.GetFullNameSignature (PropertyInfo));
3720 bool must_do_cs1540_check = false;
3721 if (getter != null &&
3722 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3723 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3724 if (pm != null && pm.HasCustomAccessModifier) {
3725 Report.SymbolRelatedToPreviousError (pm);
3726 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3727 TypeManager.CSharpSignature (getter));
3730 Report.SymbolRelatedToPreviousError (getter);
3731 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3736 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3740 // Only base will allow this invocation to happen.
3742 if (IsBase && getter.IsAbstract) {
3743 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3747 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3757 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3759 if (right_side == EmptyExpression.OutAccess) {
3760 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3761 GetSignatureForError ());
3765 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3766 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3767 GetSignatureForError ());
3771 if (setter == null){
3773 // The following condition happens if the PropertyExpr was
3774 // created, but is invalid (ie, the property is inaccessible),
3775 // and we did not want to embed the knowledge about this in
3776 // the caller routine. This only avoids double error reporting.
3780 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3781 GetSignatureForError ());
3785 if (TypeManager.GetParameterData (setter).Count != 1){
3786 Error_PropertyNotFound (setter, false);
3790 bool must_do_cs1540_check;
3791 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3792 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3793 if (pm != null && pm.HasCustomAccessModifier) {
3794 Report.SymbolRelatedToPreviousError (pm);
3795 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3796 TypeManager.CSharpSignature (setter));
3799 Report.SymbolRelatedToPreviousError (setter);
3800 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3805 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3809 // Only base will allow this invocation to happen.
3811 if (IsBase && setter.IsAbstract){
3812 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3819 public override void Emit (EmitContext ec)
3824 public void Emit (EmitContext ec, bool leave_copy)
3827 // Special case: length of single dimension array property is turned into ldlen
3829 if ((getter == TypeManager.system_int_array_get_length) ||
3830 (getter == TypeManager.int_array_get_length)){
3831 Type iet = InstanceExpression.Type;
3834 // System.Array.Length can be called, but the Type does not
3835 // support invoking GetArrayRank, so test for that case first
3837 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3839 EmitInstance (ec, false);
3840 ec.ig.Emit (OpCodes.Ldlen);
3841 ec.ig.Emit (OpCodes.Conv_I4);
3846 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3849 ec.ig.Emit (OpCodes.Dup);
3851 temp = new LocalTemporary (this.Type);
3858 // Implements the IAssignMethod interface for assignments
3860 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3862 Expression my_source = source;
3864 prepared = prepare_for_load;
3869 ec.ig.Emit (OpCodes.Dup);
3871 temp = new LocalTemporary (this.Type);
3875 } else if (leave_copy) {
3878 temp = new LocalTemporary (this.Type);
3884 ArrayList args = new ArrayList (1);
3885 args.Add (new Argument (my_source, Argument.AType.Expression));
3887 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3897 /// Fully resolved expression that evaluates to an Event
3899 public class EventExpr : MemberExpr {
3900 public readonly EventInfo EventInfo;
3903 MethodInfo add_accessor, remove_accessor;
3905 public EventExpr (EventInfo ei, Location loc)
3909 eclass = ExprClass.EventAccess;
3911 add_accessor = TypeManager.GetAddMethod (ei);
3912 remove_accessor = TypeManager.GetRemoveMethod (ei);
3913 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3916 if (EventInfo is MyEventBuilder){
3917 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3918 type = eb.EventType;
3921 type = EventInfo.EventHandlerType;
3924 public override string Name {
3926 return EventInfo.Name;
3930 public override bool IsInstance {
3936 public override bool IsStatic {
3942 public override Type DeclaringType {
3944 return EventInfo.DeclaringType;
3948 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3949 SimpleName original)
3952 // If the event is local to this class, we transform ourselves into a FieldExpr
3955 if (EventInfo.DeclaringType == ec.ContainerType ||
3956 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3957 EventField mi = TypeManager.GetEventField (EventInfo);
3960 if (!ec.IsInObsoleteScope)
3961 mi.CheckObsoleteness (loc);
3963 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
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 = source as BinaryDelegate;
4044 if (source_del == null) {
4048 Expression handler = source_del.Right;
4050 Argument arg = new Argument (handler, Argument.AType.Expression);
4051 ArrayList args = new ArrayList ();
4055 if (source_del.IsAddition)
4056 Invocation.EmitCall (
4057 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4059 Invocation.EmitCall (
4060 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4064 public class TemporaryVariable : Expression, IMemoryLocation
4069 public TemporaryVariable (Type type, Location loc)
4073 eclass = ExprClass.Value;
4076 public override Expression DoResolve (EmitContext ec)
4081 TypeExpr te = new TypeExpression (type, loc);
4082 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4083 if (!li.Resolve (ec))
4086 if (ec.MustCaptureVariable (li)) {
4087 ScopeInfo scope = li.Block.CreateScopeInfo ();
4088 var = scope.AddLocal (li);
4095 public Variable Variable {
4096 get { return var != null ? var : li.Variable; }
4099 public override void Emit (EmitContext ec)
4101 Variable.EmitInstance (ec);
4105 public void EmitLoadAddress (EmitContext ec)
4107 Variable.EmitInstance (ec);
4108 Variable.EmitAddressOf (ec);
4111 public void Store (EmitContext ec, Expression right_side)
4113 Variable.EmitInstance (ec);
4114 right_side.Emit (ec);
4115 Variable.EmitAssign (ec);
4118 public void EmitThis (EmitContext ec)
4120 Variable.EmitInstance (ec);
4123 public void EmitStore (EmitContext ec)
4125 Variable.EmitAssign (ec);
4128 public void AddressOf (EmitContext ec, AddressOp mode)
4130 EmitLoadAddress (ec);