Merge pull request #93 from konrad-kruczynski/dispatcher_timer_fix
[mono.git] / mcs / mcs / roottypes.cs
1 //
2 // roottypes.cs: keeps a tree representation of the generated code
3 //
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 //          Marek Safar  (marek.safar@gmail.com)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
11 //
12
13 using System;
14 using System.Collections.Generic;
15 using System.Runtime.InteropServices;
16 using Mono.CompilerServices.SymbolWriter;
17
18 #if STATIC
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
21 #else
22 using System.Reflection;
23 using System.Reflection.Emit;
24 #endif
25
26 namespace Mono.CSharp
27 {
28         //
29         // Module (top-level type) container
30         //
31         public sealed class ModuleContainer : TypeContainer
32         {
33 #if STATIC
34                 //
35                 // Compiler generated container for static data
36                 //
37                 sealed class StaticDataContainer : CompilerGeneratedClass
38                 {
39                         readonly Dictionary<int, Struct> size_types;
40                         new int fields;
41
42                         public StaticDataContainer (ModuleContainer module)
43                                 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
44                         {
45                                 size_types = new Dictionary<int, Struct> ();
46                         }
47
48                         public override void CloseType ()
49                         {
50                                 base.CloseType ();
51
52                                 foreach (var entry in size_types) {
53                                         entry.Value.CloseType ();
54                                 }
55                         }
56
57                         public FieldSpec DefineInitializedData (byte[] data, Location loc)
58                         {
59                                 Struct size_type;
60                                 if (!size_types.TryGetValue (data.Length, out size_type)) {
61                                         //
62                                         // Build common type for this data length. We cannot use
63                                         // DefineInitializedData because it creates public type,
64                                         // and its name is not unique among modules
65                                         //
66                                         size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
67                                         size_type.CreateType ();
68                                         size_type.DefineType ();
69
70                                         size_types.Add (data.Length, size_type);
71
72                                         // It has to work even if StructLayoutAttribute does not exist
73                                         size_type.TypeBuilder.__SetLayout (1, data.Length);
74                                 }
75
76                                 var name = "$field-" + fields.ToString ("X");
77                                 ++fields;
78                                 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
79                                 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
80                                 fbuilder.__SetDataAndRVA (data);
81
82                                 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
83                         }
84                 }
85
86                 StaticDataContainer static_data;
87
88                 //
89                 // Makes const data field inside internal type container
90                 //
91                 public FieldSpec MakeStaticData (byte[] data, Location loc)
92                 {
93                         if (static_data == null) {
94                                 static_data = new StaticDataContainer (this);
95                                 static_data.CreateType ();
96                                 static_data.DefineType ();
97
98                                 AddCompilerGeneratedClass (static_data);
99                         }
100
101                         return static_data.DefineInitializedData (data, loc);
102                 }
103 #endif
104
105                 public CharSet? DefaultCharSet;
106                 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
107
108                 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
109                 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
110                 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
111                 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
112                 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
113
114                 // Used for unique namespaces/types during parsing
115                 Dictionary<MemberName, ITypesContainer> defined_type_containers;
116
117                 AssemblyDefinition assembly;
118                 readonly CompilerContext context;
119                 readonly RootNamespace global_ns;
120                 readonly Dictionary<string, RootNamespace> alias_ns;
121
122                 ModuleBuilder builder;
123
124                 bool has_extenstion_method;
125
126                 PredefinedAttributes predefined_attributes;
127                 PredefinedTypes predefined_types;
128                 PredefinedMembers predefined_members;
129
130                 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
131
132                 public ModuleContainer (CompilerContext context)
133                         : base (null, null, MemberName.Null, null, 0)
134                 {
135                         this.context = context;
136
137                         caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
138
139                         types = new List<TypeContainer> ();
140                         anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
141                         global_ns = new GlobalRootNamespace ();
142                         alias_ns = new Dictionary<string, RootNamespace> ();
143                         array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
144                         pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
145                         reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
146                         attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
147
148                         defined_type_containers = new Dictionary<MemberName, ITypesContainer> ();
149                 }
150
151                 #region Properties
152
153                 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
154                         get {
155                                 return array_types;
156                         }
157                 }
158
159                 //
160                 // Cache for parameter-less attributes
161                 //
162                 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
163                         get {
164                                 return attrs_cache;
165                         }
166                 }
167
168                 public override AttributeTargets AttributeTargets {
169                         get {
170                                 return AttributeTargets.Assembly;
171                         }
172                 }
173
174                 public ModuleBuilder Builder {
175                         get {
176                                 return builder;
177                         }
178                 }
179
180                 public override CompilerContext Compiler {
181                         get {
182                                 return context;
183                         }
184                 }
185
186                 public override AssemblyDefinition DeclaringAssembly {
187                         get {
188                                 return assembly;
189                         }
190                 }
191
192                 internal DocumentationBuilder DocumentationBuilder {
193                         get; set;
194                 }
195
196                 public Evaluator Evaluator {
197                         get; set;
198                 }
199
200                 public bool HasDefaultCharSet {
201                         get {
202                                 return DefaultCharSet.HasValue;
203                         }
204                 }
205
206                 public bool HasExtensionMethod {
207                         get {
208                                 return has_extenstion_method;
209                         }
210                         set {
211                                 has_extenstion_method = value;
212                         }
213                 }
214
215                 public bool HasTypesFullyDefined {
216                         get; set;
217                 }
218
219                 //
220                 // Returns module global:: namespace
221                 //
222                 public RootNamespace GlobalRootNamespace {
223                     get {
224                         return global_ns;
225                     }
226                 }
227
228                 public override ModuleContainer Module {
229                         get {
230                                 return this;
231                         }
232                 }
233
234                 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
235                         get {
236                                 return pointer_types;
237                         }
238                 }
239
240                 internal PredefinedAttributes PredefinedAttributes {
241                         get {
242                                 return predefined_attributes;
243                         }
244                 }
245
246                 internal PredefinedMembers PredefinedMembers {
247                         get {
248                                 return predefined_members;
249                         }
250                 }
251
252                 internal PredefinedTypes PredefinedTypes {
253                         get {
254                                 return predefined_types;
255                         }
256                 }
257
258                 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
259                         get {
260                                 return reference_types;
261                         }
262                 }
263
264                 public override string[] ValidAttributeTargets {
265                         get {
266                                 return attribute_targets;
267                         }
268                 }
269
270                 #endregion
271
272                 public override void Accept (StructuralVisitor visitor)
273                 {
274                         visitor.Visit (this);
275                 }
276
277                 public void AddAnonymousType (AnonymousTypeClass type)
278                 {
279                         List<AnonymousTypeClass> existing;
280                         if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
281                         if (existing == null) {
282                                 existing = new List<AnonymousTypeClass> ();
283                                 anonymous_types.Add (type.Parameters.Count, existing);
284                         }
285
286                         existing.Add (type);
287                 }
288
289                 public void AddAttribute (Attribute attr, IMemberContext context)
290                 {
291                         attr.AttachTo (this, context);
292
293                         if (attributes == null) {
294                                 attributes = new Attributes (attr);
295                                 return;
296                         }
297
298                         attributes.AddAttribute (attr);
299                 }
300
301                 public override TypeContainer AddPartial (TypeContainer nextPart)
302                 {
303                         return AddPartial (nextPart, nextPart.Name);
304                 }
305
306                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
307                 {
308                         if (a.Target == AttributeTargets.Assembly) {
309                                 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
310                                 return;
311                         }
312
313                         if (a.Type == pa.DefaultCharset) {
314                                 switch (a.GetCharSetValue ()) {
315                                 case CharSet.Ansi:
316                                 case CharSet.None:
317                                         break;
318                                 case CharSet.Auto:
319                                         DefaultCharSet = CharSet.Auto;
320                                         DefaultCharSetType = TypeAttributes.AutoClass;
321                                         break;
322                                 case CharSet.Unicode:
323                                         DefaultCharSet = CharSet.Unicode;
324                                         DefaultCharSetType = TypeAttributes.UnicodeClass;
325                                         break;
326                                 default:
327                                         Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
328                                                 a.GetSignatureForError ());
329                                         break;
330                                 }
331                         } else if (a.Type == pa.CLSCompliant) {
332                                 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
333                                 if (cls == null) {
334                                         Report.Warning (3012, 1, a.Location,
335                                                 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
336                                 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
337                                         Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
338                                         Report.Warning (3017, 1, a.Location,
339                                                 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
340                                         return;
341                                 }
342                         }
343
344                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
345                 }
346
347                 public override void CloseType ()
348                 {
349                         foreach (TypeContainer tc in types) {
350                                 tc.CloseType ();
351                         }
352
353                         if (compiler_generated != null)
354                                 foreach (CompilerGeneratedClass c in compiler_generated)
355                                         c.CloseType ();
356                 }
357
358                 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
359                 {
360                         return builder.DefineType (name, attr, null, typeSize);
361                 }
362
363                 //
364                 // Creates alias global namespace
365                 //
366                 public RootNamespace CreateRootNamespace (string alias)
367                 {
368                         if (alias == global_ns.Alias) {
369                                 NamespaceContainer.Error_GlobalNamespaceRedefined (Location.Null, Report);
370                                 return global_ns;
371                         }
372
373                         RootNamespace rn;
374                         if (!alias_ns.TryGetValue (alias, out rn)) {
375                                 rn = new RootNamespace (alias);
376                                 alias_ns.Add (alias, rn);
377                         }
378
379                         return rn;
380                 }
381
382                 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
383                 {
384                         this.assembly = assembly;
385                         builder = moduleBuilder;
386                 }
387
388                 public new void CreateType ()
389                 {
390                         // Release cache used by parser only
391                         if (Evaluator == null)
392                                 defined_type_containers = null;
393                         else
394                                 defined_type_containers.Clear ();
395
396                         foreach (TypeContainer tc in types)
397                                 tc.CreateType ();
398                 }
399
400                 public new void Define ()
401                 {
402                         foreach (TypeContainer tc in types)
403                                 tc.DefineType ();
404
405                         foreach (TypeContainer tc in types)
406                                 tc.ResolveTypeParameters ();
407
408                         foreach (TypeContainer tc in types) {
409                                 try {
410                                         tc.Define ();
411                                 } catch (Exception e) {
412                                         throw new InternalErrorException (tc, e);
413                                 }
414                         }
415
416                         HasTypesFullyDefined = true;
417                 }
418
419                 public override void Emit ()
420                 {
421                         if (OptAttributes != null)
422                                 OptAttributes.Emit ();
423
424                         if (Compiler.Settings.Unsafe) {
425                                 var pa = PredefinedAttributes.UnverifiableCode;
426                                 if (pa.IsDefined)
427                                         pa.EmitAttribute (builder);
428                         }
429
430                         foreach (var tc in types)
431                                 tc.DefineConstants ();
432
433                         foreach (TypeContainer tc in types)
434                                 tc.EmitType ();
435
436                         if (Compiler.Report.Errors > 0)
437                                 return;
438
439                         foreach (TypeContainer tc in types)
440                                 tc.VerifyMembers ();
441
442                         if (compiler_generated != null)
443                                 foreach (var c in compiler_generated)
444                                         c.EmitType ();
445                 }
446
447                 internal override void GenerateDocComment (DocumentationBuilder builder)
448                 {
449                         foreach (var tc in types)
450                                 tc.GenerateDocComment (builder);
451                 }
452
453                 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
454                 {
455                         List<AnonymousTypeClass> candidates;
456                         if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
457                                 return null;
458
459                         int i;
460                         foreach (AnonymousTypeClass at in candidates) {
461                                 for (i = 0; i < parameters.Count; ++i) {
462                                         if (!parameters [i].Equals (at.Parameters [i]))
463                                                 break;
464                                 }
465
466                                 if (i == parameters.Count)
467                                         return at;
468                         }
469
470                         return null;
471                 }
472
473                 public RootNamespace GetRootNamespace (string name)
474                 {
475                         RootNamespace rn;
476                         alias_ns.TryGetValue (name, out rn);
477                         return rn;
478                 }
479
480                 public override string GetSignatureForError ()
481                 {
482                         return "<module>";
483                 }
484
485                 public void InitializePredefinedTypes ()
486                 {
487                         predefined_attributes = new PredefinedAttributes (this);
488                         predefined_types = new PredefinedTypes (this);
489                         predefined_members = new PredefinedMembers (this);
490                 }
491
492                 public override bool IsClsComplianceRequired ()
493                 {
494                         return DeclaringAssembly.IsCLSCompliant;
495                 }
496
497                 protected override bool AddMemberType (TypeContainer tc)
498                 {
499                         if (AddTypesContainer (tc)) {
500                                 if ((tc.ModFlags & Modifiers.PARTIAL) != 0)
501                                         defined_names.Add (tc.Name, tc);
502
503                                 tc.NamespaceEntry.NS.AddType (this, tc.Definition);
504                                 return true;
505                         }
506
507                         return false;
508                 }
509
510                 public bool AddTypesContainer (ITypesContainer container)
511                 {
512                         var mn = container.MemberName;
513                         ITypesContainer found;
514                         if (!defined_type_containers.TryGetValue (mn, out found)) {
515                                 defined_type_containers.Add (mn, container);
516                                 return true;
517                         }
518
519                         if (container is NamespaceContainer && found is NamespaceContainer)
520                                 return true;
521
522                         var container_tc = container as TypeContainer;
523                         var found_tc = found as TypeContainer;
524                         if (container_tc != null && found_tc != null && container_tc.Kind == found_tc.Kind) {
525                                 if ((found_tc.ModFlags & container_tc.ModFlags & Modifiers.PARTIAL) != 0) {
526                                         return false;
527                                 }
528
529                                 if (((found_tc.ModFlags | container_tc.ModFlags) & Modifiers.PARTIAL) != 0) {
530                                         Report.SymbolRelatedToPreviousError (found_tc);
531                                         Error_MissingPartialModifier (container_tc);
532                                         return false;
533                                 }
534                         }
535
536                         string ns = mn.Left != null ? mn.Left.GetSignatureForError () : Module.GlobalRootNamespace.GetSignatureForError ();
537                         mn = new MemberName (mn.Name, mn.TypeArguments, mn.Location);
538
539                         Report.SymbolRelatedToPreviousError (found.Location, "");
540                         Report.Error (101, container.Location,
541                                 "The namespace `{0}' already contains a definition for `{1}'",
542                                 ns, mn.GetSignatureForError ());
543                         return false;
544                 }
545
546                 protected override void RemoveMemberType (TypeContainer ds)
547                 {
548                         defined_type_containers.Remove (ds.MemberName);
549                         ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
550                         base.RemoveMemberType (ds);
551                 }
552
553                 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
554                 {
555                         Attribute a = OptAttributes.Search ("assembly", a_type);
556                         if (a != null) {
557                                 a.Resolve ();
558                         }
559                         return a;
560                 }
561
562                 public void SetDeclaringAssembly (AssemblyDefinition assembly)
563                 {
564                         // TODO: This setter is quite ugly but I have not found a way around it yet
565                         this.assembly = assembly;
566                 }
567         }
568
569         sealed class RootDeclSpace : TypeContainer {
570                 public RootDeclSpace (ModuleContainer module, NamespaceContainer ns)
571                         : base (ns, null, MemberName.Null, null, 0)
572                 {
573                         PartialContainer = module;
574                 }
575
576                 public override AttributeTargets AttributeTargets {
577                         get { throw new InternalErrorException ("should not be called"); }
578                 }
579
580                 public override CompilerContext Compiler {
581                         get {
582                                 return PartialContainer.Compiler;
583                         }
584                 }
585
586                 public override string DocCommentHeader {
587                         get { throw new InternalErrorException ("should not be called"); }
588                 }
589
590                 public override void DefineType ()
591                 {
592                         throw new InternalErrorException ("should not be called");
593                 }
594
595                 public override ModuleContainer Module {
596                         get {
597                                 return PartialContainer.Module;
598                         }
599                 }
600
601                 public override void Accept (StructuralVisitor visitor)
602                 {
603                         throw new InternalErrorException ("should not be called");
604                 }
605
606                 public override bool IsClsComplianceRequired ()
607                 {
608                         return PartialContainer.IsClsComplianceRequired ();
609                 }
610
611                 public override ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
612                 {
613                         return null;
614                 }
615
616                 public override FullNamedExpression LookupNamespaceAlias (string name)
617                 {
618                         return NamespaceEntry.LookupNamespaceAlias (name);
619                 }
620         }
621 }