X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fdecl.cs;h=77a3929ae89e7de6165dce3b84fc75dc9d34c10c;hb=e0df8328d11d79623c1b0369cf15544b26a18db0;hp=7341c4925cb3ebd079ab0cd4a7fe92fbdde00e6a;hpb=dee9438306afc7114ffa0f7edf7eeec25d240adf;p=mono.git diff --git a/mcs/mcs/decl.cs b/mcs/mcs/decl.cs index 7341c4925cb..77a3929ae89 100644 --- a/mcs/mcs/decl.cs +++ b/mcs/mcs/decl.cs @@ -13,6 +13,7 @@ // using System; +using System.Text; using System.Collections; using System.Globalization; using System.Reflection.Emit; @@ -28,14 +29,17 @@ namespace Mono.CSharp { public class MemberName { public readonly string Name; + public readonly TypeArguments TypeArguments; + public readonly MemberName Left; public readonly Location Location; - bool is_double_colon; - public static readonly MemberName Null = new MemberName (""); - private MemberName (MemberName left, string name, bool is_double_colon, Location loc) + bool is_double_colon; + + private MemberName (MemberName left, string name, bool is_double_colon, + Location loc) { this.Name = name; this.Location = loc; @@ -43,62 +47,69 @@ namespace Mono.CSharp { this.Left = left; } - public MemberName (string name) - : this (null, name, false, Location.Null) + private MemberName (MemberName left, string name, bool is_double_colon, + TypeArguments args, Location loc) + : this (left, name, is_double_colon, loc) { + this.TypeArguments = args; } - public MemberName (MemberName left, string name) - : this (left, name, false, left != null ? left.Location : Location.Null) - { - } + public MemberName (string name) + : this (name, Location.Null) + { } public MemberName (string name, Location loc) : this (null, name, false, loc) - { - } + { } + + public MemberName (string name, TypeArguments args, Location loc) + : this (null, name, false, args, loc) + { } + + public MemberName (MemberName left, string name) + : this (left, name, left != null ? left.Location : Location.Null) + { } public MemberName (MemberName left, string name, Location loc) : this (left, name, false, loc) - { - } + { } + + public MemberName (MemberName left, string name, TypeArguments args, Location loc) + : this (left, name, false, args, loc) + { } public MemberName (string alias, string name, Location loc) - : this (new MemberName (alias), name, true, loc) - { - } + : this (new MemberName (alias, loc), name, true, loc) + { } public MemberName (MemberName left, MemberName right) : this (left, right, right.Location) - { - } + { } public MemberName (MemberName left, MemberName right, Location loc) - : this (null, right.Name, false, loc) + : this (null, right.Name, false, right.TypeArguments, loc) { if (right.is_double_colon) throw new InternalErrorException ("Cannot append double_colon member name"); this.Left = (right.Left == null) ? left : new MemberName (left, right.Left); } - static readonly char [] dot_array = { '.' }; - - public static MemberName FromDotted (string name) - { - string [] elements = name.Split (dot_array); - int count = elements.Length; - int i = 0; - MemberName n = new MemberName (elements [i++]); - while (i < count) - n = new MemberName (n, elements [i++]); - return n; - } - public string GetName () { return GetName (false); } + public bool IsGeneric { + get { + if (TypeArguments != null) + return true; + else if (Left != null) + return Left.IsGeneric; + else + return false; + } + } + public string GetName (bool is_generic) { string name = is_generic ? Basename : Name; @@ -109,32 +120,33 @@ namespace Mono.CSharp { return name; } - /// - /// This returns exclusively the name as seen on the source code - /// it is not the fully qualifed type after resolution - /// - public string GetPartialName () - { - string connect = is_double_colon ? "::" : "."; - if (Left != null) - return Left.GetPartialName () + connect + Name; - else - return Name; - } - public string GetTypeName () { string connect = is_double_colon ? "::" : "."; if (Left != null) - return Left.GetTypeName () + connect + Name; + return Left.GetTypeName () + connect + MakeName (Name, TypeArguments); else - return Name; + return MakeName (Name, TypeArguments); } public Expression GetTypeExpression () { - if (Left == null) +#if GMCS_SOURCE + if (IsUnbound) { + if (!CheckUnbound (Location)) + return null; + + return new UnboundTypeExpression (this, Location); + } +#endif + + if (Left == null) { + if (TypeArguments != null) + return new SimpleName (Basename, TypeArguments, Location); + else return new SimpleName (Name, Location); + } + if (is_double_colon) { if (Left.Left != null) throw new InternalErrorException ("The left side of a :: should be an identifier"); @@ -142,26 +154,50 @@ namespace Mono.CSharp { } Expression lexpr = Left.GetTypeExpression (); - return new MemberAccess (lexpr, Name, Location); + return new MemberAccess (lexpr, Name, TypeArguments, Location); } public MemberName Clone () { MemberName left_clone = Left == null ? null : Left.Clone (); - return new MemberName (left_clone, Name, is_double_colon, Location); + return new MemberName (left_clone, Name, is_double_colon, TypeArguments, Location); } public string Basename { - get { return Name; } + get { + if (TypeArguments != null) + return MakeName (Name, TypeArguments); + else + return Name; + } + } + + public string FullName { + get { + if (TypeArguments != null) + return Name + "<" + TypeArguments + ">"; + else + return Name; + } + } + + public string MethodName { + get { + string connect = is_double_colon ? "::" : "."; + if (Left != null) + return Left.FullName + connect + Name; + else + return Name; + } } public override string ToString () { string connect = is_double_colon ? "::" : "."; if (Left != null) - return Left + connect + Name; + return Left.FullName + connect + FullName; else - return Name; + return FullName; } public override bool Equals (object other) @@ -177,13 +213,14 @@ namespace Mono.CSharp { return false; if (is_double_colon != other.is_double_colon) return false; -#if NET_2_0 - if (TypeArguments == null) - return other.TypeArguments == null; - if (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count) + if ((TypeArguments != null) && + (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count)) return false; -#endif + + if ((TypeArguments == null) && (other.TypeArguments != null)) + return false; + if (Left == null) return other.Left == null; @@ -197,20 +234,64 @@ namespace Mono.CSharp { hash ^= n.Name.GetHashCode (); if (is_double_colon) hash ^= 0xbadc01d; -#if NET_2_0 + if (TypeArguments != null) hash ^= TypeArguments.Count << 5; -#endif return hash & 0x7FFFFFFF; } + + public int CountTypeArguments { + get { + if (TypeArguments == null) + return 0; + else + return TypeArguments.Count; + } + } + + public static string MakeName (string name, TypeArguments args) + { + if (args == null) + return name; + else + return name + "`" + args.Count; + } + + public static string MakeName (string name, int count) + { + return name + "`" + count; + } + + protected bool IsUnbound { + get { + if ((Left != null) && Left.IsUnbound) + return true; + else if (TypeArguments == null) + return false; + else + return TypeArguments.IsUnbound; + } + } + + protected bool CheckUnbound (Location loc) + { + if ((Left != null) && !Left.CheckUnbound (loc)) + return false; + if ((TypeArguments != null) && !TypeArguments.IsUnbound) { + Report.Error (1031, loc, "Type expected"); + return false; + } + + return true; + } } /// /// Base representation for members. This is used to keep track /// of Name, Location and Modifier flags, and handling Attributes. /// - public abstract class MemberCore : Attributable { + public abstract class MemberCore : Attributable, IResolveContext { /// /// Public name /// @@ -219,7 +300,7 @@ namespace Mono.CSharp { public string Name { get { if (cached_name == null) - cached_name = MemberName.GetName (false); + cached_name = MemberName.GetName (!(this is GenericMethod) && !(this is Method)); return cached_name; } } @@ -235,7 +316,7 @@ namespace Mono.CSharp { /// public int ModFlags; - public /*readonly*/ TypeContainer Parent; + public readonly DeclSpace Parent; /// /// Location where this declaration happens @@ -247,7 +328,7 @@ namespace Mono.CSharp { /// /// XML documentation comment /// - public string DocComment; + protected string comment; /// /// Represents header string for documentation comment @@ -269,7 +350,8 @@ namespace Mono.CSharp { Excluded = 1 << 9, // Method is conditional TestMethodDuplication = 1 << 10, // Test for duplication must be performed IsUsed = 1 << 11, - IsAssigned = 1 << 12 // Field is assigned + IsAssigned = 1 << 12, // Field is assigned + HasExplicitLayout = 1 << 13 } /// @@ -277,13 +359,10 @@ namespace Mono.CSharp { /// internal Flags caching_flags; - public MemberCore (TypeContainer parent, MemberName name, Attributes attrs) + public MemberCore (DeclSpace parent, MemberName name, Attributes attrs) : base (attrs) { - if (parent is PartialContainer && !(this is PartialContainer)) - throw new InternalErrorException ("A PartialContainer cannot be the direct parent of a member"); - - Parent = parent; + this.Parent = parent; member_name = name; caching_flags = Flags.Obsolete_Undetected | Flags.ClsCompliance_Undetected | Flags.HasCompliantAttribute_Undetected | Flags.Excluded_Undetected; } @@ -294,32 +373,26 @@ namespace Mono.CSharp { cached_name = null; } - /// - /// Tests presence of ObsoleteAttribute and report proper error - /// - protected void CheckUsageOfObsoleteAttribute (Type type) - { - if (type == null) - return; - - ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (type); - if (obsolete_attr == null) - return; + public abstract bool Define (); - AttributeTester.Report_ObsoleteMessage (obsolete_attr, type.FullName, Location); + public virtual string DocComment { + get { + return comment; + } + set { + comment = value; + } } - public abstract bool Define (); - // // Returns full member name for error message // public virtual string GetSignatureForError () { if (Parent == null || Parent.Parent == null) - return Name; + return member_name.ToString (); - return String.Concat (Parent.GetSignatureForError (), '.', Name); + return String.Concat (Parent.GetSignatureForError (), '.', member_name.ToString ()); } /// @@ -327,26 +400,14 @@ namespace Mono.CSharp { /// public virtual void Emit () { - // Hack with Parent == null is for EnumMember - if (Parent == null || (GetObsoleteAttribute (Parent) == null && Parent.GetObsoleteAttribute (Parent) == null)) - VerifyObsoleteAttribute (); - if (!RootContext.VerifyClsCompliance) return; - VerifyClsCompliance (Parent); - } - - public bool InUnsafe { - get { - return ((ModFlags & Modifiers.UNSAFE) != 0) || Parent.UnsafeContext; - } + VerifyClsCompliance (); } public virtual bool IsUsed { - get { - return (caching_flags & Flags.IsUsed) != 0; - } + get { return (caching_flags & Flags.IsUsed) != 0; } } public void SetMemberIsUsed () @@ -354,28 +415,10 @@ namespace Mono.CSharp { caching_flags |= Flags.IsUsed; } - // - // Whehter is it ok to use an unsafe pointer in this type container - // - public bool UnsafeOK (DeclSpace parent) - { - // - // First check if this MemberCore modifier flags has unsafe set - // - if ((ModFlags & Modifiers.UNSAFE) != 0) - return true; - - if (parent.UnsafeContext) - return true; - - Expression.UnsafeError (Location); - return false; - } - /// /// Returns instance of ObsoleteAttribute for this MemberCore /// - public ObsoleteAttribute GetObsoleteAttribute (DeclSpace ds) + public virtual ObsoleteAttribute GetObsoleteAttribute () { // ((flags & (Flags.Obsolete_Undetected | Flags.Obsolete)) == 0) is slower, but why ? if ((caching_flags & Flags.Obsolete_Undetected) == 0 && (caching_flags & Flags.Obsolete) == 0) { @@ -388,11 +431,11 @@ namespace Mono.CSharp { return null; Attribute obsolete_attr = OptAttributes.Search ( - TypeManager.obsolete_attribute_type, ds.EmitContext); + TypeManager.obsolete_attribute_type); if (obsolete_attr == null) return null; - ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute (ds.EmitContext); + ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute (); if (obsolete == null) return null; @@ -403,9 +446,12 @@ namespace Mono.CSharp { /// /// Checks for ObsoleteAttribute presence. It's used for testing of all non-types elements /// - public void CheckObsoleteness (Location loc) + public virtual void CheckObsoleteness (Location loc) { - ObsoleteAttribute oa = GetObsoleteAttribute (Parent); + if (Parent != null) + Parent.CheckObsoleteness (loc); + + ObsoleteAttribute oa = GetObsoleteAttribute (); if (oa == null) { return; } @@ -416,12 +462,12 @@ namespace Mono.CSharp { /// /// Analyze whether CLS-Compliant verification must be execute for this MemberCore. /// - public override bool IsClsCompliaceRequired (DeclSpace container) + public override bool IsClsComplianceRequired () { if ((caching_flags & Flags.ClsCompliance_Undetected) == 0) return (caching_flags & Flags.ClsCompliant) != 0; - if (GetClsCompliantAttributeValue (container) && IsExposedFromAssembly (container)) { + if (GetClsCompliantAttributeValue () && IsExposedFromAssembly ()) { caching_flags &= ~Flags.ClsCompliance_Undetected; caching_flags |= Flags.ClsCompliant; return true; @@ -434,12 +480,12 @@ namespace Mono.CSharp { /// /// Returns true when MemberCore is exposed from assembly. /// - public bool IsExposedFromAssembly (DeclSpace ds) + public bool IsExposedFromAssembly () { if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0) return false; - DeclSpace parentContainer = ds; + DeclSpace parentContainer = Parent; while (parentContainer != null && parentContainer.ModFlags != 0) { if ((parentContainer.ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0) return false; @@ -449,19 +495,33 @@ namespace Mono.CSharp { } /// - /// Resolve CLSCompliantAttribute value or gets cached value. + /// Goes through class hierarchy and gets value of first found CLSCompliantAttribute. + /// If no is attribute exists then assembly CLSCompliantAttribute is returned. /// - bool GetClsCompliantAttributeValue (DeclSpace ds) + public virtual bool GetClsCompliantAttributeValue () { + if ((caching_flags & Flags.HasCompliantAttribute_Undetected) == 0) + return (caching_flags & Flags.ClsCompliantAttributeTrue) != 0; + + caching_flags &= ~Flags.HasCompliantAttribute_Undetected; + if (OptAttributes != null) { Attribute cls_attribute = OptAttributes.Search ( - TypeManager.cls_compliant_attribute_type, ds.EmitContext); + TypeManager.cls_compliant_attribute_type); if (cls_attribute != null) { caching_flags |= Flags.HasClsCompliantAttribute; - return cls_attribute.GetClsCompliantAttributeValue (ds.EmitContext); + bool value = cls_attribute.GetClsCompliantAttributeValue (); + if (value) + caching_flags |= Flags.ClsCompliantAttributeTrue; + return value; } } - return ds.GetClsCompliantAttributeValue (); + + if (Parent.GetClsCompliantAttributeValue ()) { + caching_flags |= Flags.ClsCompliantAttributeTrue; + return true; + } + return false; } /// @@ -487,14 +547,14 @@ namespace Mono.CSharp { /// CLS-Compliant which means that CLS-Compliant tests are not necessary. A descendants override it /// and add their extra verifications. /// - protected virtual bool VerifyClsCompliance (DeclSpace ds) + protected virtual bool VerifyClsCompliance () { - if (!IsClsCompliaceRequired (ds)) { + if (!IsClsComplianceRequired ()) { if (HasClsCompliantAttribute && RootContext.WarningLevel >= 2) { - if (!IsExposedFromAssembly (ds)) - Report.Warning (3019, Location, "CLS compliance checking will not be performed on `{0}' because it is not visible from outside this assembly", GetSignatureForError ()); + if (!IsExposedFromAssembly ()) + Report.Warning (3019, 2, Location, "CLS compliance checking will not be performed on `{0}' because it is not visible from outside this assembly", GetSignatureForError ()); if (!CodeGen.Assembly.IsClsCompliant) - Report.Warning (3021, Location, "`{0}' does not need a CLSCompliant attribute because the assembly is not marked as CLS-compliant", GetSignatureForError ()); + Report.Warning (3021, 2, Location, "`{0}' does not need a CLSCompliant attribute because the assembly is not marked as CLS-compliant", GetSignatureForError ()); } return false; } @@ -514,13 +574,11 @@ namespace Mono.CSharp { return true; } - protected abstract void VerifyObsoleteAttribute (); - // // Raised (and passed an XmlElement that contains the comment) // when GenerateDocComment is writing documentation expectedly. // - internal virtual void OnGenerateDocComment (DeclSpace ds, XmlElement intermediateNode) + internal virtual void OnGenerateDocComment (XmlElement intermediateNode) { } @@ -544,6 +602,40 @@ namespace Mono.CSharp { { DocUtil.GenerateDocComment (this, ds); } + + public override IResolveContext ResolveContext { + get { return this; } + } + + #region IResolveContext Members + + public DeclSpace DeclContainer { + get { return Parent; } + } + + public virtual DeclSpace GenericDeclContainer { + get { return DeclContainer; } + } + + public bool IsInObsoleteScope { + get { + if (GetObsoleteAttribute () != null) + return true; + + return Parent == null ? false : Parent.IsInObsoleteScope; + } + } + + public bool IsInUnsafeScope { + get { + if ((ModFlags & Modifiers.UNSAFE) != 0) + return true; + + return Parent == null ? false : Parent.IsInUnsafeScope; + } + } + + #endregion } /// @@ -561,6 +653,13 @@ namespace Mono.CSharp { /// public TypeBuilder TypeBuilder; + /// + /// If we are a generic type, this is the type we are + /// currently defining. We need to lookup members on this + /// instead of the TypeBuilder. + /// + public Type CurrentType; + // // This is the namespace in which this typecontainer // was declared. We use this to resolve names. @@ -569,39 +668,57 @@ namespace Mono.CSharp { private Hashtable Cache = new Hashtable (); - public string Basename; + public readonly string Basename; protected Hashtable defined_names; - // The emit context for toplevel objects. - protected EmitContext ec; - - public EmitContext EmitContext { - get { return ec; } + public TypeContainer PartialContainer; + + readonly bool is_generic; + readonly int count_type_params; + readonly int count_current_type_params; + + // + // Whether we are Generic + // + public bool IsGeneric { + get { + if (is_generic) + return true; + else if (Parent != null) + return Parent.IsGeneric; + else + return false; + } } static string[] attribute_targets = new string [] { "type" }; - public DeclSpace (NamespaceEntry ns, TypeContainer parent, MemberName name, + public DeclSpace (NamespaceEntry ns, DeclSpace parent, MemberName name, Attributes attrs) : base (parent, name, attrs) { NamespaceEntry = ns; - Basename = name.Name; + Basename = name.Basename; defined_names = new Hashtable (); + PartialContainer = null; + if (name.TypeArguments != null) { + is_generic = true; + count_type_params = count_current_type_params = name.TypeArguments.Count; + } + if (parent != null) + count_type_params += parent.count_type_params; + } + + public override DeclSpace GenericDeclContainer { + get { return this; } } /// /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts /// - protected bool AddToContainer (MemberCore symbol, string name) + protected virtual bool AddToContainer (MemberCore symbol, string name) { - if (name == Basename && !(this is Interface) && !(this is Enum)) { - Report.SymbolRelatedToPreviousError (this); - Report.Error (542, symbol.Location, "`{0}': member names cannot be the same as their enclosing type", symbol.GetSignatureForError ()); - return false; - } - MemberCore mc = (MemberCore) defined_names [name]; if (mc == null) { @@ -613,10 +730,8 @@ namespace Mono.CSharp { return true; Report.SymbolRelatedToPreviousError (mc); - if (symbol is PartialContainer || mc is PartialContainer) { - Report.Error (260, symbol.Location, - "Missing partial modifier on declaration of type `{0}'. Another partial declaration of this type exists", - name); + if ((mc.ModFlags & Modifiers.PARTIAL) != 0 && (symbol is ClassOrStruct || symbol is Interface)) { + Error_MissingPartialModifier (symbol); return false; } @@ -624,10 +739,15 @@ namespace Mono.CSharp { Report.Error (101, symbol.Location, "The namespace `{0}' already contains a definition for `{1}'", ((DeclSpace)symbol).NamespaceEntry.GetSignatureForError (), symbol.MemberName.Name); + } else if (symbol is TypeParameter) { + Report.Error (692, symbol.Location, + "Duplicate type parameter `{0}'", name); } else { - Report.Error (102, symbol.Location, "The type `{0}' already contains a definition for `{1}'", - GetSignatureForError (), symbol.MemberName.Name); + Report.Error (102, symbol.Location, + "The type `{0}' already contains a definition for `{1}'", + GetSignatureForError (), symbol.MemberName.Name); } + return false; } @@ -684,7 +804,7 @@ namespace Mono.CSharp { /// Define all members, but don't apply any attributes or do anything which may /// access not-yet-defined classes. This method also creates the MemberCache. /// - public virtual bool DefineMembers (TypeContainer parent) + public virtual bool DefineMembers () { if (((ModFlags & Modifiers.NEW) != 0) && IsTopLevel) { Report.Error (1530, Location, "Keyword `new' is not allowed on namespace elements"); @@ -693,59 +813,43 @@ namespace Mono.CSharp { return true; } + protected void Error_MissingPartialModifier (MemberCore type) + { + Report.Error (260, type.Location, + "Missing partial modifier on declaration of type `{0}'. Another partial declaration of this type exists", + type.GetSignatureForError ()); + } + public override string GetSignatureForError () { + if (IsGeneric) { + return SimpleName.RemoveGenericArity (Name) + TypeParameter.GetSignatureForError (CurrentTypeParameters); + } // Parent.GetSignatureForError return Name; } - - // - // Whether this is an `unsafe context' - // - public bool UnsafeContext { - get { - if ((ModFlags & Modifiers.UNSAFE) != 0) - return true; - if (Parent != null) - return Parent.UnsafeContext; - return false; - } - } - - EmitContext type_resolve_ec; - protected EmitContext TypeResolveEmitContext { - get { - if (type_resolve_ec == null) { - // FIXME: I think this should really be one of: - // - // a. type_resolve_ec = Parent.EmitContext; - // b. type_resolve_ec = new EmitContext (Parent, Parent, loc, null, null, ModFlags, false); - // - // However, if Parent == RootContext.Tree.Types, its NamespaceEntry will be null. - // - type_resolve_ec = new EmitContext (Parent, this, Location.Null, null, null, ModFlags, false); - } - return type_resolve_ec; - } - } - - // - // Resolves the expression `e' for a type, and will recursively define - // types. This should only be used for resolving base types. - // - public TypeExpr ResolveBaseTypeExpr (Expression e, bool silent, Location loc) - { - TypeResolveEmitContext.loc = loc; - TypeResolveEmitContext.ContainerType = TypeBuilder; - - return e.ResolveAsTypeTerminal (TypeResolveEmitContext, silent); - } public bool CheckAccessLevel (Type check_type) { - if (check_type == TypeBuilder) + TypeBuilder tb; + if (this is GenericMethod) + tb = Parent.TypeBuilder; + else + tb = TypeBuilder; + + check_type = TypeManager.DropGenericTypeArguments (check_type); + if (check_type == tb) return true; + if (TypeBuilder == null) + // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases(). + // However, this is invoked again later -- so safe to return true. + // May also be null when resolving top-level attributes. + return true; + + if (TypeManager.IsGenericParameter (check_type)) + return true; // FIXME + TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask; // @@ -756,41 +860,48 @@ namespace Mono.CSharp { if (check_type.IsArray || check_type.IsPointer) return CheckAccessLevel (TypeManager.GetElementType (check_type)); - if (TypeBuilder == null) - // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases(). - // However, this is invoked again later -- so safe to return true. - // May also be null when resolving top-level attributes. - return true; - switch (check_attr){ case TypeAttributes.Public: return true; case TypeAttributes.NotPublic: + + if (TypeBuilder == null) + // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases(). + // However, this is invoked again later -- so safe to return true. + // May also be null when resolving top-level attributes. + return true; // // This test should probably use the declaringtype. // - return check_type.Assembly == TypeBuilder.Assembly; + return check_type.Assembly == TypeBuilder.Assembly || + TypeManager.IsFriendAssembly (check_type.Assembly); case TypeAttributes.NestedPublic: return true; case TypeAttributes.NestedPrivate: - return NestedAccessible (check_type); + return NestedAccessible (tb, check_type); case TypeAttributes.NestedFamily: - return FamilyAccessible (check_type); + // + // Only accessible to methods in current type or any subtypes + // + return FamilyAccessible (tb, check_type); case TypeAttributes.NestedFamANDAssem: - return (check_type.Assembly == TypeBuilder.Assembly) && - FamilyAccessible (check_type); + return ((check_type.Assembly == tb.Assembly) || + TypeManager.IsFriendAssembly (check_type.Assembly)) && + FamilyAccessible (tb, check_type); case TypeAttributes.NestedFamORAssem: - return (check_type.Assembly == TypeBuilder.Assembly) || - FamilyAccessible (check_type); + return (check_type.Assembly == tb.Assembly) || + FamilyAccessible (tb, check_type) || + TypeManager.IsFriendAssembly (check_type.Assembly); case TypeAttributes.NestedAssembly: - return check_type.Assembly == TypeBuilder.Assembly; + return check_type.Assembly == tb.Assembly || + TypeManager.IsFriendAssembly (check_type.Assembly); } Console.WriteLine ("HERE: " + check_attr); @@ -798,14 +909,14 @@ namespace Mono.CSharp { } - protected bool NestedAccessible (Type check_type) + protected bool NestedAccessible (Type tb, Type check_type) { Type declaring = check_type.DeclaringType; return TypeBuilder == declaring || TypeManager.IsNestedChildOf (TypeBuilder, declaring); } - protected bool FamilyAccessible (Type check_type) + protected bool FamilyAccessible (Type tb, Type check_type) { Type declaring = check_type.DeclaringType; return TypeManager.IsNestedFamilyAccessible (TypeBuilder, declaring); @@ -814,7 +925,7 @@ namespace Mono.CSharp { // Access level of a type. const int X = 1; enum AccessLevel { // Each column represents `is this scope larger or equal to Blah scope' - // Public Assembly Protected + // Public Assembly Protected Protected = (0 << 0) | (0 << 1) | (X << 2), Public = (X << 0) | (X << 1) | (X << 2), Private = (0 << 0) | (0 << 1) | (0 << 2), @@ -833,10 +944,8 @@ namespace Mono.CSharp { } else if ((flags & Modifiers.PROTECTED) != 0) return AccessLevel.Protected; - else if ((flags & Modifiers.PRIVATE) != 0) return AccessLevel.Private; - else return AccessLevel.Public; } @@ -848,8 +957,7 @@ namespace Mono.CSharp { AccessLevel myAccess = GetAccessLevelFromModifiers (ModFlags); if (!IsTopLevel && (Parent != null)) return myAccess & Parent.EffectiveAccessLevel; - else - return myAccess; + return myAccess; } } @@ -857,7 +965,7 @@ namespace Mono.CSharp { static AccessLevel TypeEffectiveAccessLevel (Type t) { if (t.IsPublic) - return AccessLevel.Public; + return AccessLevel.Public; if (t.IsNestedPrivate) return AccessLevel.Private; if (t.IsNotPublic) @@ -888,6 +996,9 @@ namespace Mono.CSharp { // public bool AsAccessible (Type p, int flags) { + if (TypeManager.IsGenericParameter (p)) + return true; // FIXME + // // 1) if M is private, its accessability is the same as this declspace. // we already know that P is accessible to T before this method, so we @@ -912,15 +1023,6 @@ namespace Mono.CSharp { return ~ (~ mAccess | pAccess) == 0; } - // - // Return the nested type with name @name. Ensures that the nested type - // is defined if necessary. Do _not_ use this when you have a MemberCache handy. - // - public virtual Type FindNestedType (string name) - { - return null; - } - private Type LookupNestedTypeInHierarchy (string name) { // if the member cache has been created, lets use it. @@ -933,11 +1035,13 @@ namespace Mono.CSharp { for (Type current_type = TypeBuilder; current_type != null && current_type != TypeManager.object_type; current_type = current_type.BaseType) { + current_type = TypeManager.DropGenericTypeArguments (current_type); if (current_type is TypeBuilder) { - DeclSpace decl = this; - if (current_type != TypeBuilder) - decl = TypeManager.LookupDeclSpace (current_type); - t = decl.FindNestedType (name); + TypeContainer tc = current_type == TypeBuilder + ? PartialContainer + : TypeManager.LookupTypeContainer (current_type); + if (tc != null) + t = tc.FindNestedType (name); } else { t = TypeManager.GetNestedType (current_type, name); } @@ -958,9 +1062,6 @@ namespace Mono.CSharp { // public FullNamedExpression LookupType (string name, Location loc, bool ignore_cs0104) { - if (this is PartialContainer) - throw new InternalErrorException ("Should not get here"); - if (Cache.Contains (name)) return (FullNamedExpression) Cache [name]; @@ -968,7 +1069,7 @@ namespace Mono.CSharp { Type t = LookupNestedTypeInHierarchy (name); if (t != null) e = new TypeExpression (t, Location.Null); - else if (Parent != null && Parent != RootContext.Tree.Types) + else if (Parent != null) e = Parent.LookupType (name, loc, ignore_cs0104); else e = NamespaceEntry.LookupNamespaceOrType (this, name, loc, ignore_cs0104); @@ -1002,54 +1103,207 @@ namespace Mono.CSharp { TypeBuilder.SetCustomAttribute (cb); } - /// - /// Goes through class hierarchy and get value of first CLSCompliantAttribute that found. - /// If no is attribute exists then return assembly CLSCompliantAttribute. - /// - public bool GetClsCompliantAttributeValue () + // + // Extensions for generics + // + TypeParameter[] type_params; + TypeParameter[] type_param_list; + + protected string GetInstantiationName () { - if ((caching_flags & Flags.HasCompliantAttribute_Undetected) == 0) - return (caching_flags & Flags.ClsCompliantAttributeTrue) != 0; + StringBuilder sb = new StringBuilder (Name); + sb.Append ("<"); + for (int i = 0; i < type_param_list.Length; i++) { + if (i > 0) + sb.Append (","); + sb.Append (type_param_list [i].Name); + } + sb.Append (">"); + return sb.ToString (); + } - caching_flags &= ~Flags.HasCompliantAttribute_Undetected; + bool check_type_parameter (ArrayList list, int start, string name) + { + for (int i = 0; i < start; i++) { + TypeParameter param = (TypeParameter) list [i]; - if (OptAttributes != null) { - Attribute cls_attribute = OptAttributes.Search (TypeManager.cls_compliant_attribute_type, ec); - if (cls_attribute != null) { - caching_flags |= Flags.HasClsCompliantAttribute; - if (cls_attribute.GetClsCompliantAttributeValue (ec)) { - caching_flags |= Flags.ClsCompliantAttributeTrue; - return true; + if (param.Name != name) + continue; + + Report.SymbolRelatedToPreviousError (Parent); + // TODO: Location is wrong (parent instead of child) + Report.Warning (693, 3, Location, + "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'", + name, Parent.GetSignatureForError ()); + + return false; + } + + return true; + } + + TypeParameter[] initialize_type_params () + { + if (type_param_list != null) + return type_param_list; + + DeclSpace the_parent = Parent; + if (this is GenericMethod) + the_parent = null; + + int start = 0; + TypeParameter[] parent_params = null; + if ((the_parent != null) && the_parent.IsGeneric) { + parent_params = the_parent.initialize_type_params (); + start = parent_params != null ? parent_params.Length : 0; + } + + ArrayList list = new ArrayList (); + if (parent_params != null) + list.AddRange (parent_params); + + int count = type_params != null ? type_params.Length : 0; + for (int i = 0; i < count; i++) { + TypeParameter param = type_params [i]; + check_type_parameter (list, start, param.Name); + list.Add (param); + } + + type_param_list = new TypeParameter [list.Count]; + list.CopyTo (type_param_list, 0); + return type_param_list; + } + + public virtual void SetParameterInfo (ArrayList constraints_list) + { + if (!is_generic) { + if (constraints_list != null) { + Report.Error ( + 80, Location, "Constraints are not allowed " + + "on non-generic declarations"); + } + + return; + } + + TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations (); + type_params = new TypeParameter [names.Length]; + + // + // Register all the names + // + for (int i = 0; i < type_params.Length; i++) { + TypeParameterName name = names [i]; + + Constraints constraints = null; + if (constraints_list != null) { + int total = constraints_list.Count; + for (int ii = 0; ii < total; ++ii) { + Constraints constraints_at = (Constraints)constraints_list[ii]; + // TODO: it is used by iterators only + if (constraints_at == null) { + constraints_list.RemoveAt (ii); + --total; + continue; + } + if (constraints_at.TypeParameter == name.Name) { + constraints = constraints_at; + constraints_list.RemoveAt(ii); + break; + } } - return false; } + + type_params [i] = new TypeParameter ( + Parent, this, name.Name, constraints, name.OptAttributes, + Location); + + AddToContainer (type_params [i], name.Name); } - if (Parent == null) { - if (CodeGen.Assembly.IsClsCompliant) { - caching_flags |= Flags.ClsCompliantAttributeTrue; - return true; + if (constraints_list != null && constraints_list.Count > 0) { + foreach (Constraints constraint in constraints_list) { + Report.Error(699, constraint.Location, "`{0}': A constraint references nonexistent type parameter `{1}'", + GetSignatureForError (), constraint.TypeParameter); } - return false; } + } - if (Parent.GetClsCompliantAttributeValue ()) { - caching_flags |= Flags.ClsCompliantAttributeTrue; - return true; + public TypeParameter[] TypeParameters { + get { + if (!IsGeneric) + throw new InvalidOperationException (); + if (type_param_list == null) + initialize_type_params (); + + return type_param_list; + } + } + + public TypeParameter[] CurrentTypeParameters { + get { + if (!IsGeneric) + throw new InvalidOperationException (); + if (type_params != null) + return type_params; + else + return new TypeParameter [0]; + } + } + + public int CountTypeParameters { + get { + return count_type_params; } - return false; + } + + public int CountCurrentTypeParameters { + get { + return count_current_type_params; + } + } + + public TypeParameterExpr LookupGeneric (string name, Location loc) + { + if (!IsGeneric) + return null; + + TypeParameter [] current_params; + if (this is TypeContainer) + current_params = PartialContainer.CurrentTypeParameters; + else + current_params = CurrentTypeParameters; + + foreach (TypeParameter type_param in current_params) { + if (type_param.Name == name) + return new TypeParameterExpr (type_param, loc); + } + + if (Parent != null) + return Parent.LookupGeneric (name, loc); + + return null; } public override string[] ValidAttributeTargets { get { return attribute_targets; } } - protected override bool VerifyClsCompliance (DeclSpace ds) + protected override bool VerifyClsCompliance () { - if (!base.VerifyClsCompliance (ds)) { + if (!base.VerifyClsCompliance ()) { return false; } + if (type_params != null) { + foreach (TypeParameter tp in type_params) { + if (tp.Constraints == null) + continue; + + tp.Constraints.VerifyClsCompliance (); + } + } + IDictionary cache = TypeManager.AllClsTopLevelTypes; string lcase = Name.ToLower (System.Globalization.CultureInfo.InvariantCulture); if (!cache.Contains (lcase)) { @@ -1065,12 +1319,13 @@ namespace Mono.CSharp { Report.SymbolRelatedToPreviousError (t); } else { - if (val is PartialContainer) - return true; - Report.SymbolRelatedToPreviousError ((DeclSpace)val); } +#if GMCS_SOURCE + Report.Warning (3005, 1, Location, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ()); +#else Report.Error (3005, Location, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ()); +#endif return true; } } @@ -1323,6 +1578,8 @@ namespace Mono.CSharp { // method cache with all declared and inherited methods. Type type = container.Type; if (!(type is TypeBuilder) && !type.IsInterface && + // !(type.IsGenericType && (type.GetGenericTypeDefinition () is TypeBuilder)) && + !TypeManager.IsGenericType (type) && (Container.BaseCache == null || Container.BaseCache.method_hash != null)) { method_hash = new Hashtable (); AddMethods (type); @@ -1353,7 +1610,7 @@ namespace Mono.CSharp { /// /// Bootstrap this member cache by doing a deep-copy of our base. /// - Hashtable SetupCache (MemberCache base_class) + static Hashtable SetupCache (MemberCache base_class) { Hashtable hash = new Hashtable (); @@ -1431,6 +1688,10 @@ namespace Mono.CSharp { foreach (MemberInfo member in members) { string name = member.Name; + int pos = name.IndexOf ('<'); + if (pos > 0) + name = name.Substring (0, pos); + // We use a name-based hash table of ArrayList's. ArrayList list = (ArrayList) member_hash [name]; if (list == null) { @@ -1701,6 +1962,7 @@ namespace Mono.CSharp { IMemberContainer current = Container; + bool do_interface_search = current.IsInterface; // `applicable' is a list of all members with the given member name `name' // in the current class and all its base classes. The list is sorted in @@ -1716,7 +1978,10 @@ namespace Mono.CSharp { // iteration of this loop if there are no members with the name we're // looking for in the current class). if (entry.Container != current) { - if (declared_only || DoneSearching (global)) + if (declared_only) + break; + + if (!do_interface_search && DoneSearching (global)) break; current = entry.Container; @@ -1732,8 +1997,28 @@ namespace Mono.CSharp { // Apply the filter to it. if (filter (entry.Member, criteria)) { - if ((entry.EntryType & EntryType.MaskType) != EntryType.Method) + if ((entry.EntryType & EntryType.MaskType) != EntryType.Method) { do_method_search = false; + } + + // Because interfaces support multiple inheritance we have to be sure that + // base member is from same interface, so only top level member will be returned + if (do_interface_search && global.Count > 0) { + bool member_already_exists = false; + + foreach (MemberInfo mi in global) { + if (mi is MethodBase) + continue; + + if (IsInterfaceBaseInterface (TypeManager.GetInterfaces (mi.DeclaringType), entry.Member.DeclaringType)) { + member_already_exists = true; + break; + } + } + if (member_already_exists) + continue; + } + global.Add (entry.Member); } } @@ -1755,6 +2040,22 @@ namespace Mono.CSharp { global.CopyTo (copy); return copy; } + + /// + /// Returns true if iterface exists in any base interfaces (ifaces) + /// + static bool IsInterfaceBaseInterface (Type[] ifaces, Type ifaceToFind) + { + foreach (Type iface in ifaces) { + if (iface == ifaceToFind) + return true; + + Type[] base_ifaces = TypeManager.GetInterfaces (iface); + if (base_ifaces.Length > 0 && IsInterfaceBaseInterface (base_ifaces, ifaceToFind)) + return true; + } + return false; + } // find the nested type @name in @this. public Type FindNestedType (string name) @@ -1780,7 +2081,7 @@ namespace Mono.CSharp { // Because the MemberCache holds members from this class and all the base classes, // we can avoid tons of reflection stuff. // - public MemberInfo FindMemberToOverride (Type invocationType, string name, Type [] paramTypes, bool is_property) + public MemberInfo FindMemberToOverride (Type invocationType, string name, Type [] paramTypes, GenericMethod genericMethod, bool is_property) { ArrayList applicable; if (method_hash != null && !is_property) @@ -1817,31 +2118,32 @@ namespace Mono.CSharp { } } else { mi = (MethodInfo) entry.Member; - cmpAttrs = TypeManager.GetArgumentTypes (mi); + cmpAttrs = TypeManager.GetParameterData (mi).Types; } if (fi != null) { // TODO: Almost duplicate ! // Check visibility switch (fi.Attributes & FieldAttributes.FieldAccessMask) { - case FieldAttributes.Private: - // - // A private method is Ok if we are a nested subtype. - // The spec actually is not very clear about this, see bug 52458. - // - if (invocationType != entry.Container.Type & - TypeManager.IsNestedChildOf (invocationType, entry.Container.Type)) - continue; - - break; - case FieldAttributes.FamANDAssem: - case FieldAttributes.Assembly: - // - // Check for assembly methods - // - if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder) - continue; - break; + case FieldAttributes.PrivateScope: + continue; + case FieldAttributes.Private: + // + // A private method is Ok if we are a nested subtype. + // The spec actually is not very clear about this, see bug 52458. + // + if (!invocationType.Equals (entry.Container.Type) && + !TypeManager.IsNestedChildOf (invocationType, entry.Container.Type)) + continue; + break; + case FieldAttributes.FamANDAssem: + case FieldAttributes.Assembly: + // + // Check for assembly methods + // + if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder) + continue; + break; } return entry.Member; } @@ -1852,10 +2154,24 @@ namespace Mono.CSharp { if (cmpAttrs.Length != paramTypes.Length) continue; - for (int j = cmpAttrs.Length - 1; j >= 0; j --) - if (paramTypes [j] != cmpAttrs [j]) - goto next; - + int j; + for (j = 0; j < cmpAttrs.Length; ++j) + if (!TypeManager.IsEqual (paramTypes [j], cmpAttrs [j])) + break; + if (j < cmpAttrs.Length) + continue; + + // + // check generic arguments for methods + // + if (mi != null) { + Type [] cmpGenArgs = TypeManager.GetGenericArguments (mi); + if (genericMethod == null && cmpGenArgs.Length != 0) + continue; + if (genericMethod != null && cmpGenArgs.Length != genericMethod.TypeParameters.Length) + continue; + } + // // get one of the methods because this has the visibility info. // @@ -1869,34 +2185,27 @@ namespace Mono.CSharp { // Check visibility // switch (mi.Attributes & MethodAttributes.MemberAccessMask) { + case MethodAttributes.PrivateScope: + continue; case MethodAttributes.Private: // // A private method is Ok if we are a nested subtype. // The spec actually is not very clear about this, see bug 52458. // - if (invocationType == entry.Container.Type || - TypeManager.IsNestedChildOf (invocationType, entry.Container.Type)) - return entry.Member; - + if (!invocationType.Equals (entry.Container.Type) && + !TypeManager.IsNestedChildOf (invocationType, entry.Container.Type)) + continue; break; case MethodAttributes.FamANDAssem: case MethodAttributes.Assembly: // // Check for assembly methods // - if (mi.DeclaringType.Assembly == CodeGen.Assembly.Builder) - return entry.Member; - + if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder) + continue; break; - default: - // - // A protected method is ok, because we are overriding. - // public is always ok. - // - return entry.Member; } - next: - ; + return entry.Member; } return null; @@ -2013,7 +2322,9 @@ namespace Mono.CSharp { /// /// Cls compliance check whether methods or constructors parameters differing only in ref or out, or in array rank /// - public void VerifyClsParameterConflict (ArrayList al, MethodCore method, MemberInfo this_builder) + /// + // TODO: refactor as method is always 'this' + public static void VerifyClsParameterConflict (ArrayList al, MethodCore method, MemberInfo this_builder) { EntryType tested_type = (method is Constructor ? EntryType.Constructor : EntryType.Method) | EntryType.Public; @@ -2029,7 +2340,7 @@ namespace Mono.CSharp { MethodBase method_to_compare = (MethodBase)entry.Member; AttributeTester.Result result = AttributeTester.AreOverloadedMethodParamsClsCompliant ( - method.ParameterTypes, TypeManager.GetArgumentTypes (method_to_compare)); + method.ParameterTypes, TypeManager.GetParameterData (method_to_compare).Types); if (result == AttributeTester.Result.Ok) continue; @@ -2038,7 +2349,7 @@ namespace Mono.CSharp { // TODO: now we are ignoring CLSCompliance(false) on method from other assembly which is buggy. // However it is exactly what csc does. - if (md != null && !md.IsClsCompliaceRequired (method.Parent)) + if (md != null && !md.IsClsComplianceRequired ()) continue; Report.SymbolRelatedToPreviousError (entry.Member);