Don't emit reaonly. prefix for reference loads
[mono.git] / mcs / mcs / roottypes.cs
index a26900c0756eb94a7729e90569d805733e35b3e7..df7962043c9088089aa24c0c70a8e059e3384662 100644 (file)
@@ -1,7 +1,8 @@
 //
 // roottypes.cs: keeps a tree representation of the generated code
 //
-// Author: Miguel de Icaza (miguel@gnu.org)
+// Authors: Miguel de Icaza (miguel@gnu.org)
+//          Marek Safar  (marek.safar@gmail.com)
 //
 // Dual licensed under the terms of the MIT X11 or GNU GPL
 //
 //
 
 using System;
-using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Mono.CompilerServices.SymbolWriter;
+
+#if STATIC
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+#else
 using System.Reflection;
 using System.Reflection.Emit;
-using System.IO;
+#endif
 
 namespace Mono.CSharp
 {
-       // <summary>
-       //   We store here all the toplevel types that we have parsed,
-       //   this is the root of all information we have parsed.
-       // </summary>
-       public sealed class RootTypes : TypeContainer
+       //
+       // Module (top-level type) container
+       //
+       public sealed class ModuleContainer : TypeContainer
        {
-               // TODO: It'd be so nice to have generics
-               Hashtable anonymous_types;
-               
-               public RootTypes ()
-                       : base (null, null, MemberName.Null, null, Kind.Root)
+#if STATIC
+               //
+               // Compiler generated container for static data
+               //
+               sealed class StaticDataContainer : CompilerGeneratedClass
+               {
+                       readonly Dictionary<int, Struct> size_types;
+                       new int fields;
+
+                       public StaticDataContainer (ModuleContainer module)
+                               : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
+                       {
+                               size_types = new Dictionary<int, Struct> ();
+                       }
+
+                       public override void CloseType ()
+                       {
+                               base.CloseType ();
+
+                               foreach (var entry in size_types) {
+                                       entry.Value.CloseType ();
+                               }
+                       }
+
+                       public FieldSpec DefineInitializedData (byte[] data, Location loc)
+                       {
+                               Struct size_type;
+                               if (!size_types.TryGetValue (data.Length, out size_type)) {
+                                       //
+                                       // Build common type for this data length. We cannot use
+                                       // DefineInitializedData because it creates public type,
+                                       // and its name is not unique among modules
+                                       //
+                                       size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
+                                       size_type.CreateType ();
+                                       size_type.DefineType ();
+
+                                       size_types.Add (data.Length, size_type);
+
+                                       // It has to work even if StructLayoutAttribute does not exist
+                                       size_type.TypeBuilder.__SetLayout (1, data.Length);
+                               }
+
+                               var name = "$field-" + fields.ToString ("X");
+                               ++fields;
+                               const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
+                               var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
+                               fbuilder.__SetDataAndRVA (data);
+
+                               return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
+                       }
+               }
+
+               StaticDataContainer static_data;
+
+               //
+               // Makes const data field inside internal type container
+               //
+               public FieldSpec MakeStaticData (byte[] data, Location loc)
+               {
+                       if (static_data == null) {
+                               static_data = new StaticDataContainer (this);
+                               static_data.CreateType ();
+                               static_data.DefineType ();
+
+                               AddCompilerGeneratedClass (static_data);
+                       }
+
+                       return static_data.DefineInitializedData (data, loc);
+               }
+#endif
+
+               public CharSet? DefaultCharSet;
+               public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
+
+               readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
+               readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
+               readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
+               readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
+               readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
+
+               // Used for unique namespaces/types during parsing
+               Dictionary<MemberName, ITypesContainer> defined_type_containers;
+
+               AssemblyDefinition assembly;
+               readonly CompilerContext context;
+               readonly RootNamespace global_ns;
+               readonly Dictionary<string, RootNamespace> alias_ns;
+
+               ModuleBuilder builder;
+
+               bool has_extenstion_method;
+
+               PredefinedAttributes predefined_attributes;
+               PredefinedTypes predefined_types;
+               PredefinedMembers predefined_members;
+
+               static readonly string[] attribute_targets = new string[] { "assembly", "module" };
+
+               public ModuleContainer (CompilerContext context)
+                       : base (null, null, MemberName.Null, null, 0)
+               {
+                       this.context = context;
+
+                       caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
+
+                       types = new List<TypeContainer> ();
+                       anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
+                       global_ns = new GlobalRootNamespace ();
+                       alias_ns = new Dictionary<string, RootNamespace> ();
+                       array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
+                       pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
+                       reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
+                       attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
+
+                       defined_type_containers = new Dictionary<MemberName, ITypesContainer> ();
+               }
+
+               #region Properties
+
+               internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
+                       get {
+                               return array_types;
+                       }
+               }
+
+               //
+               // Cache for parameter-less attributes
+               //
+               internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
+                       get {
+                               return attrs_cache;
+                       }
+               }
+
+               public override AttributeTargets AttributeTargets {
+                       get {
+                               return AttributeTargets.Assembly;
+                       }
+               }
+
+               public ModuleBuilder Builder {
+                       get {
+                               return builder;
+                       }
+               }
+
+               public override CompilerContext Compiler {
+                       get {
+                               return context;
+                       }
+               }
+
+               public override AssemblyDefinition DeclaringAssembly {
+                       get {
+                               return assembly;
+                       }
+               }
+
+               internal DocumentationBuilder DocumentationBuilder {
+                       get; set;
+               }
+
+               public Evaluator Evaluator {
+                       get; set;
+               }
+
+               public bool HasDefaultCharSet {
+                       get {
+                               return DefaultCharSet.HasValue;
+                       }
+               }
+
+               public bool HasExtensionMethod {
+                       get {
+                               return has_extenstion_method;
+                       }
+                       set {
+                               has_extenstion_method = value;
+                       }
+               }
+
+               public bool HasTypesFullyDefined {
+                       get; set;
+               }
+
+               //
+               // Returns module global:: namespace
+               //
+               public RootNamespace GlobalRootNamespace {
+                   get {
+                       return global_ns;
+                   }
+               }
+
+               public override ModuleContainer Module {
+                       get {
+                               return this;
+                       }
+               }
+
+               internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
+                       get {
+                               return pointer_types;
+                       }
+               }
+
+               internal PredefinedAttributes PredefinedAttributes {
+                       get {
+                               return predefined_attributes;
+                       }
+               }
+
+               internal PredefinedMembers PredefinedMembers {
+                       get {
+                               return predefined_members;
+                       }
+               }
+
+               internal PredefinedTypes PredefinedTypes {
+                       get {
+                               return predefined_types;
+                       }
+               }
+
+               internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
+                       get {
+                               return reference_types;
+                       }
+               }
+
+               public override string[] ValidAttributeTargets {
+                       get {
+                               return attribute_targets;
+                       }
+               }
+
+               #endregion
+
+               public override void Accept (StructuralVisitor visitor)
                {
-                       types = new ArrayList ();
-                       anonymous_types = new Hashtable ();
+                       visitor.Visit (this);
                }
 
                public void AddAnonymousType (AnonymousTypeClass type)
                {
-                       ArrayList existing = (ArrayList)anonymous_types [type.Parameters.Count];
+                       List<AnonymousTypeClass> existing;
+                       if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
                        if (existing == null) {
-                               existing = new ArrayList ();
+                               existing = new List<AnonymousTypeClass> ();
                                anonymous_types.Add (type.Parameters.Count, existing);
                        }
+
                        existing.Add (type);
                }
 
-               public override bool IsClsComplianceRequired ()
+               public void AddAttribute (Attribute attr, IMemberContext context)
                {
-                       return true;
+                       attr.AttachTo (this, context);
+
+                       if (attributes == null) {
+                               attributes = new Attributes (attr);
+                               return;
+                       }
+
+                       attributes.AddAttribute (attr);
                }
 
-               public AnonymousTypeClass GetAnonymousType (ArrayList parameters)
+               public override TypeContainer AddPartial (TypeContainer nextPart)
                {
-                       ArrayList candidates = (ArrayList) anonymous_types [parameters.Count];
-                       if (candidates == null)
+                       return AddPartial (nextPart, nextPart.Name);
+               }
+
+               public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
+               {
+                       if (a.Target == AttributeTargets.Assembly) {
+                               assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
+                               return;
+                       }
+
+                       if (a.Type == pa.DefaultCharset) {
+                               switch (a.GetCharSetValue ()) {
+                               case CharSet.Ansi:
+                               case CharSet.None:
+                                       break;
+                               case CharSet.Auto:
+                                       DefaultCharSet = CharSet.Auto;
+                                       DefaultCharSetType = TypeAttributes.AutoClass;
+                                       break;
+                               case CharSet.Unicode:
+                                       DefaultCharSet = CharSet.Unicode;
+                                       DefaultCharSetType = TypeAttributes.UnicodeClass;
+                                       break;
+                               default:
+                                       Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
+                                               a.GetSignatureForError ());
+                                       break;
+                               }
+                       } else if (a.Type == pa.CLSCompliant) {
+                               Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
+                               if (cls == null) {
+                                       Report.Warning (3012, 1, a.Location,
+                                               "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
+                               } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
+                                       Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
+                                       Report.Warning (3017, 1, a.Location,
+                                               "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
+                                       return;
+                               }
+                       }
+
+                       builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
+               }
+
+               public override void CloseType ()
+               {
+                       foreach (TypeContainer tc in types) {
+                               tc.CloseType ();
+                       }
+
+                       if (compiler_generated != null)
+                               foreach (CompilerGeneratedClass c in compiler_generated)
+                                       c.CloseType ();
+               }
+
+               public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
+               {
+                       return builder.DefineType (name, attr, null, typeSize);
+               }
+
+               //
+               // Creates alias global namespace
+               //
+               public RootNamespace CreateRootNamespace (string alias)
+               {
+                       if (alias == global_ns.Alias) {
+                               NamespaceContainer.Error_GlobalNamespaceRedefined (Location.Null, Report);
+                               return global_ns;
+                       }
+
+                       RootNamespace rn;
+                       if (!alias_ns.TryGetValue (alias, out rn)) {
+                               rn = new RootNamespace (alias);
+                               alias_ns.Add (alias, rn);
+                       }
+
+                       return rn;
+               }
+
+               public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
+               {
+                       this.assembly = assembly;
+                       builder = moduleBuilder;
+               }
+
+               public new void CreateType ()
+               {
+                       // Release cache used by parser only
+                       if (Evaluator == null)
+                               defined_type_containers = null;
+                       else
+                               defined_type_containers.Clear ();
+
+                       foreach (TypeContainer tc in types)
+                               tc.CreateType ();
+               }
+
+               public new void Define ()
+               {
+                       foreach (TypeContainer tc in types)
+                               tc.DefineType ();
+
+                       foreach (TypeContainer tc in types)
+                               tc.ResolveTypeParameters ();
+
+                       foreach (TypeContainer tc in types) {
+                               try {
+                                       tc.Define ();
+                               } catch (Exception e) {
+                                       throw new InternalErrorException (tc, e);
+                               }
+                       }
+
+                       HasTypesFullyDefined = true;
+               }
+
+               public override void Emit ()
+               {
+                       if (OptAttributes != null)
+                               OptAttributes.Emit ();
+
+                       if (Compiler.Settings.Unsafe) {
+                               var pa = PredefinedAttributes.UnverifiableCode;
+                               if (pa.IsDefined)
+                                       pa.EmitAttribute (builder);
+                       }
+
+                       foreach (var tc in types)
+                               tc.DefineConstants ();
+
+                       foreach (TypeContainer tc in types)
+                               tc.EmitType ();
+
+                       if (Compiler.Report.Errors > 0)
+                               return;
+
+                       foreach (TypeContainer tc in types)
+                               tc.VerifyMembers ();
+
+                       if (compiler_generated != null)
+                               foreach (var c in compiler_generated)
+                                       c.EmitType ();
+               }
+
+               internal override void GenerateDocComment (DocumentationBuilder builder)
+               {
+                       foreach (var tc in types)
+                               tc.GenerateDocComment (builder);
+               }
+
+               public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
+               {
+                       List<AnonymousTypeClass> candidates;
+                       if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
                                return null;
 
                        int i;
@@ -68,74 +470,152 @@ namespace Mono.CSharp
                        return null;
                }
 
-               public override bool GetClsCompliantAttributeValue ()
+               public RootNamespace GetRootNamespace (string name)
                {
-                       return CodeGen.Assembly.IsClsCompliant;
+                       RootNamespace rn;
+                       alias_ns.TryGetValue (name, out rn);
+                       return rn;
                }
 
                public override string GetSignatureForError ()
                {
-                       return "";
+                       return "<module>";
+               }
+
+               public void InitializePredefinedTypes ()
+               {
+                       predefined_attributes = new PredefinedAttributes (this);
+                       predefined_types = new PredefinedTypes (this);
+                       predefined_members = new PredefinedMembers (this);
+               }
+
+               public override bool IsClsComplianceRequired ()
+               {
+                       return DeclaringAssembly.IsCLSCompliant;
+               }
+
+               protected override bool AddMemberType (TypeContainer tc)
+               {
+                       if (AddTypesContainer (tc)) {
+                               if ((tc.ModFlags & Modifiers.PARTIAL) != 0)
+                                       defined_names.Add (tc.Name, tc);
+
+                               tc.NamespaceEntry.NS.AddType (this, tc.Definition);
+                               return true;
+                       }
+
+                       return false;
                }
 
-               protected override bool AddMemberType (DeclSpace ds)
+               public bool AddTypesContainer (ITypesContainer container)
                {
-                       if (!AddToContainer (ds, ds.Name))
-                               return false;
-                       ds.NamespaceEntry.NS.AddDeclSpace (ds.Basename, ds);
-                       return true;
+                       var mn = container.MemberName;
+                       ITypesContainer found;
+                       if (!defined_type_containers.TryGetValue (mn, out found)) {
+                               defined_type_containers.Add (mn, container);
+                               return true;
+                       }
+
+                       if (container is NamespaceContainer && found is NamespaceContainer)
+                               return true;
+
+                       var container_tc = container as TypeContainer;
+                       var found_tc = found as TypeContainer;
+                       if (container_tc != null && found_tc != null && container_tc.Kind == found_tc.Kind) {
+                               if ((found_tc.ModFlags & container_tc.ModFlags & Modifiers.PARTIAL) != 0) {
+                                       return false;
+                               }
+
+                               if (((found_tc.ModFlags | container_tc.ModFlags) & Modifiers.PARTIAL) != 0) {
+                                       Report.SymbolRelatedToPreviousError (found_tc);
+                                       Error_MissingPartialModifier (container_tc);
+                                       return false;
+                               }
+                       }
+
+                       string ns = mn.Left != null ? mn.Left.GetSignatureForError () : Module.GlobalRootNamespace.GetSignatureForError ();
+                       mn = new MemberName (mn.Name, mn.TypeArguments, mn.Location);
+
+                       Report.SymbolRelatedToPreviousError (found.Location, "");
+                       Report.Error (101, container.Location,
+                               "The namespace `{0}' already contains a definition for `{1}'",
+                               ns, mn.GetSignatureForError ());
+                       return false;
                }
 
-               protected override void RemoveMemberType (DeclSpace ds)
+               protected override void RemoveMemberType (TypeContainer ds)
                {
+                       defined_type_containers.Remove (ds.MemberName);
                        ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
                        base.RemoveMemberType (ds);
                }
-               
-               public override TypeContainer AddPartial (TypeContainer nextPart)
+
+               public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
                {
-                       return AddPartial (nextPart, nextPart.Name);
+                       Attribute a = OptAttributes.Search ("assembly", a_type);
+                       if (a != null) {
+                               a.Resolve ();
+                       }
+                       return a;
                }
 
+               public void SetDeclaringAssembly (AssemblyDefinition assembly)
+               {
+                       // TODO: This setter is quite ugly but I have not found a way around it yet
+                       this.assembly = assembly;
+               }
        }
 
-       public class RootDeclSpace : DeclSpace {
-               public RootDeclSpace (NamespaceEntry ns)
-                       : base (ns, null, MemberName.Null, null)
+       sealed class RootDeclSpace : TypeContainer {
+               public RootDeclSpace (ModuleContainer module, NamespaceContainer ns)
+                       : base (ns, null, MemberName.Null, null, 0)
                {
-                       PartialContainer = RootContext.ToplevelTypes;
+                       PartialContainer = module;
                }
 
                public override AttributeTargets AttributeTargets {
                        get { throw new InternalErrorException ("should not be called"); }
                }
 
+               public override CompilerContext Compiler {
+                       get {
+                               return PartialContainer.Compiler;
+                       }
+               }
+
                public override string DocCommentHeader {
                        get { throw new InternalErrorException ("should not be called"); }
                }
 
-               public override bool Define ()
+               public override void DefineType ()
                {
                        throw new InternalErrorException ("should not be called");
                }
 
-               public override TypeBuilder DefineType ()
+               public override ModuleContainer Module {
+                       get {
+                               return PartialContainer.Module;
+                       }
+               }
+
+               public override void Accept (StructuralVisitor visitor)
                {
                        throw new InternalErrorException ("should not be called");
                }
 
-               public override MemberCache MemberCache {
-                       get { return PartialContainer.MemberCache; }
+               public override bool IsClsComplianceRequired ()
+               {
+                       return PartialContainer.IsClsComplianceRequired ();
                }
 
-               public override bool GetClsCompliantAttributeValue ()
+               public override IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceContainer scope)
                {
-                       return PartialContainer.GetClsCompliantAttributeValue ();
+                       return null;
                }
 
-               public override bool IsClsComplianceRequired ()
+               public override FullNamedExpression LookupNamespaceAlias (string name)
                {
-                       return PartialContainer.IsClsComplianceRequired ();
+                       return NamespaceEntry.LookupNamespaceAlias (name);
                }
        }
 }