Merge remote branch 'upstream/master'
[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 class ModuleContainer : TypeContainer
32         {
33                 //
34                 // Compiler generated container for static data
35                 //
36                 sealed class StaticDataContainer : CompilerGeneratedClass
37                 {
38                         Dictionary<int, Struct> size_types;
39                         new int fields;
40 #if !STATIC
41                         static MethodInfo set_data;
42 #endif
43
44                         public StaticDataContainer (ModuleContainer module)
45                                 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
46                         {
47                                 size_types = new Dictionary<int, Struct> ();
48                         }
49
50                         public override void CloseType ()
51                         {
52                                 base.CloseType ();
53
54                                 foreach (var entry in size_types) {
55                                         entry.Value.CloseType ();
56                                 }
57                         }
58
59                         public FieldSpec DefineInitializedData (byte[] data, Location loc)
60                         {
61                                 Struct size_type;
62                                 if (!size_types.TryGetValue (data.Length, out size_type)) {
63                                         //
64                                         // Build common type for this data length. We cannot use
65                                         // DefineInitializedData because it creates public type,
66                                         // and its name is not unique among modules
67                                         //
68                                         size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, Location), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
69                                         size_type.CreateType ();
70                                         size_type.DefineType ();
71
72                                         size_types.Add (data.Length, size_type);
73
74                                         var pa = Module.PredefinedAttributes.StructLayout;
75                                         if (pa.Constructor != null || pa.ResolveConstructor (Location, TypeManager.short_type)) {
76                                                 var argsEncoded = new AttributeEncoder (false);
77                                                 argsEncoded.Encode ((short) LayoutKind.Explicit);
78
79                                                 var field_size = pa.GetField ("Size", TypeManager.int32_type, Location);
80                                                 var pack = pa.GetField ("Pack", TypeManager.int32_type, Location);
81                                                 if (field_size != null) {
82                                                         argsEncoded.EncodeNamedArguments (
83                                                                 new[] { field_size, pack },
84                                                                 new[] { new IntConstant ((int) data.Length, Location), new IntConstant (1, Location) }
85                                                         );
86                                                 }
87
88                                                 pa.EmitAttribute (size_type.TypeBuilder, argsEncoded);
89                                         }
90                                 }
91
92                                 var name = "$field-" + fields.ToString ("X");
93                                 ++fields;
94                                 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
95                                 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
96 #if STATIC
97                                 fbuilder.__SetDataAndRVA (data);
98 #else
99                                 if (set_data == null)
100                                         set_data = typeof (FieldBuilder).GetMethod ("SetRVAData", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
101
102                                 try {
103                                         set_data.Invoke (fbuilder, new object[] { data });
104                                 } catch {
105                                         Report.RuntimeMissingSupport (loc, "SetRVAData");
106                                 }
107 #endif
108
109                                 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
110                         }
111                 }
112
113                 public CharSet DefaultCharSet = CharSet.Ansi;
114                 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
115
116                 Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
117                 StaticDataContainer static_data;
118
119                 AssemblyDefinition assembly;
120                 readonly CompilerContext context;
121                 readonly RootNamespace global_ns;
122                 Dictionary<string, RootNamespace> alias_ns;
123
124                 ModuleBuilder builder;
125
126                 // HACK
127                 public List<Enum> hack_corlib_enums = new List<Enum> ();
128
129                 bool has_default_charset;
130                 bool has_extenstion_method;
131
132                 PredefinedAttributes predefined_attributes;
133                 PredefinedTypes predefined_types;
134
135                 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
136
137                 public ModuleContainer (CompilerContext context)
138                         : base (null, null, MemberName.Null, null, 0)
139                 {
140                         this.context = context;
141
142                         caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
143
144                         types = new List<TypeContainer> ();
145                         anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
146                         global_ns = new GlobalRootNamespace ();
147                         alias_ns = new Dictionary<string, RootNamespace> ();
148                 }
149
150                 #region Properties
151
152                 public override AttributeTargets AttributeTargets {
153                         get {
154                                 return AttributeTargets.Assembly;
155                         }
156                 }
157
158                 public ModuleBuilder Builder {
159                         get {
160                                 return builder;
161                         }
162                 }
163
164                 public override CompilerContext Compiler {
165                         get {
166                                 return context;
167                         }
168                 }
169
170                 public override AssemblyDefinition DeclaringAssembly {
171                         get {
172                                 return assembly;
173                         }
174                 }
175
176                 public bool HasDefaultCharSet {
177                         get {
178                                 return has_default_charset;
179                         }
180                 }
181
182                 public bool HasExtensionMethod {
183                         get {
184                                 return has_extenstion_method;
185                         }
186                         set {
187                                 has_extenstion_method = value;
188                         }
189                 }
190
191                 //
192                 // Returns module global:: namespace
193                 //
194                 public RootNamespace GlobalRootNamespace {
195                     get {
196                         return global_ns;
197                     }
198                 }
199
200                 public override ModuleContainer Module {
201                         get {
202                                 return this;
203                         }
204                 }
205
206                 internal PredefinedAttributes PredefinedAttributes {
207                         get {
208                                 return predefined_attributes;
209                         }
210                 }
211
212                 internal PredefinedTypes PredefinedTypes {
213                         get {
214                                 return predefined_types;
215                         }
216                 }
217
218                 public override string[] ValidAttributeTargets {
219                         get {
220                                 return attribute_targets;
221                         }
222                 }
223
224                 #endregion
225
226                 public void AddAnonymousType (AnonymousTypeClass type)
227                 {
228                         List<AnonymousTypeClass> existing;
229                         if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
230                         if (existing == null) {
231                                 existing = new List<AnonymousTypeClass> ();
232                                 anonymous_types.Add (type.Parameters.Count, existing);
233                         }
234
235                         existing.Add (type);
236                 }
237
238                 public void AddAttributes (List<Attribute> attrs)
239                 {
240                         AddAttributes (attrs, this);
241                 }
242
243                 public void AddAttributes (List<Attribute> attrs, IMemberContext context)
244                 {
245                         foreach (Attribute a in attrs)
246                                 a.AttachTo (this, context);
247
248                         if (attributes == null) {
249                                 attributes = new Attributes (attrs);
250                                 return;
251                         }
252                         attributes.AddAttributes (attrs);
253                 }
254
255                 public override TypeContainer AddPartial (TypeContainer nextPart)
256                 {
257                         return AddPartial (nextPart, nextPart.Name);
258                 }
259
260                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
261                 {
262                         if (a.Target == AttributeTargets.Assembly) {
263                                 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
264                                 return;
265                         }
266
267                         if (a.Type == pa.CLSCompliant) {
268                                 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
269                                 if (cls == null) {
270                                         Report.Warning (3012, 1, a.Location,
271                                                 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
272                                 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
273                                         Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
274                                         Report.Warning (3017, 1, a.Location,
275                                                 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
276                                         return;
277                                 }
278                         }
279
280                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
281                 }
282
283                 public override void CloseType ()
284                 {
285                         HackCorlibEnums ();
286
287                         foreach (TypeContainer tc in types) {
288                                 tc.CloseType ();
289                         }
290
291                         if (compiler_generated != null)
292                                 foreach (CompilerGeneratedClass c in compiler_generated)
293                                         c.CloseType ();
294                 }
295
296                 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
297                 {
298                         return builder.DefineType (name, attr, null, typeSize);
299                 }
300
301                 //
302                 // Creates alias global namespace
303                 //
304                 public RootNamespace CreateRootNamespace (string alias)
305                 {
306                         if (alias == global_ns.Alias) {
307                                 NamespaceEntry.Error_GlobalNamespaceRedefined (Location.Null, Report);
308                                 return global_ns;
309                         }
310
311                         RootNamespace rn;
312                         if (!alias_ns.TryGetValue (alias, out rn)) {
313                                 rn = new RootNamespace (alias);
314                                 alias_ns.Add (alias, rn);
315                         }
316
317                         return rn;
318                 }
319
320                 public new void Define ()
321                 {
322                         builder = assembly.CreateModuleBuilder ();
323
324                         // FIXME: Temporary hack for repl to reset
325                         static_data = null;
326
327                         // TODO: It should be done much later when the types are resolved
328                         // but that require DefineType clean-up
329                         ResolveGlobalAttributes ();
330
331                         foreach (TypeContainer tc in types)
332                                 tc.CreateType ();
333
334                         InitializePredefinedTypes ();
335
336                         foreach (TypeContainer tc in types)
337                                 tc.DefineType ();
338
339                         foreach (TypeContainer tc in types)
340                                 tc.ResolveTypeParameters ();
341
342                         foreach (TypeContainer tc in types) {
343                                 try {
344                                         tc.Define ();
345                                 } catch (Exception e) {
346                                         throw new InternalErrorException (tc, e);
347                                 }
348                         }
349                 }
350
351                 public override void Emit ()
352                 {
353                         if (OptAttributes != null)
354                                 OptAttributes.Emit ();
355
356                         if (RootContext.Unsafe) {
357                                 var pa = PredefinedAttributes.UnverifiableCode;
358                                 if (pa.IsDefined)
359                                         pa.EmitAttribute (builder);
360                         }
361
362                         foreach (var tc in types)
363                                 tc.DefineConstants ();
364
365                         HackCorlib ();
366
367                         foreach (TypeContainer tc in types)
368                                 tc.EmitType ();
369
370                         if (Compiler.Report.Errors > 0)
371                                 return;
372
373                         foreach (TypeContainer tc in types)
374                                 tc.VerifyMembers ();
375
376                         if (compiler_generated != null)
377                                 foreach (var c in compiler_generated)
378                                         c.EmitType ();
379                 }
380
381                 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
382                 {
383                         List<AnonymousTypeClass> candidates;
384                         if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
385                                 return null;
386
387                         int i;
388                         foreach (AnonymousTypeClass at in candidates) {
389                                 for (i = 0; i < parameters.Count; ++i) {
390                                         if (!parameters [i].Equals (at.Parameters [i]))
391                                                 break;
392                                 }
393
394                                 if (i == parameters.Count)
395                                         return at;
396                         }
397
398                         return null;
399                 }
400
401                 public RootNamespace GetRootNamespace (string name)
402                 {
403                         RootNamespace rn;
404                         alias_ns.TryGetValue (name, out rn);
405                         return rn;
406                 }
407
408                 public override string GetSignatureForError ()
409                 {
410                         return "<module>";
411                 }
412
413                 void HackCorlib ()
414                 {
415 #if !STATIC
416                         if (RootContext.StdLib)
417                                 return;
418
419                         //
420                         // HACK: When building corlib mcs uses loaded mscorlib which
421                         // has different predefined types and this method sets mscorlib types
422                         // to be same to avoid type check errors in CreateType.
423                         //
424                         var type = typeof (Type);
425                         var system_4_type_arg = new[] { type, type, type, type };
426
427                         MethodInfo set_corlib_type_builders =
428                                 typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod (
429                                 "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null,
430                                 system_4_type_arg, null);
431
432                         if (set_corlib_type_builders == null) {
433                                 Compiler.Report.Warning (-26, 3,
434                                         "The compilation may fail due to missing `System.Reflection.Emit.AssemblyBuilder.SetCorlibTypeBuilders(...)' method");
435                                 return;
436                         }
437
438                         object[] args = new object[4];
439                         args[0] = TypeManager.object_type.GetMetaInfo ();
440                         args[1] = TypeManager.value_type.GetMetaInfo ();
441                         args[2] = TypeManager.enum_type.GetMetaInfo ();
442                         args[3] = TypeManager.void_type.GetMetaInfo ();
443                         set_corlib_type_builders.Invoke (assembly.Builder, args);
444 #endif
445                 }
446
447                 void HackCorlibEnums ()
448                 {
449                         if (RootContext.StdLib)
450                                 return;
451
452                         // Another Mono corlib HACK
453                         // mono_class_layout_fields requires to have enums created
454                         // before creating a class which used the enum for any of its fields
455                         foreach (var e in hack_corlib_enums)
456                                 e.CloseType ();
457                 }
458
459                 public void InitializePredefinedTypes ()
460                 {
461                         predefined_attributes = new PredefinedAttributes (this);
462                         predefined_types = new PredefinedTypes (this);
463                 }
464
465                 public override bool IsClsComplianceRequired ()
466                 {
467                         return DeclaringAssembly.IsCLSCompliant;
468                 }
469
470                 //
471                 // Makes const data field inside internal type container
472                 //
473                 public FieldSpec MakeStaticData (byte[] data, Location loc)
474                 {
475                         if (static_data == null) {
476                                 static_data = new StaticDataContainer (this);
477                                 static_data.CreateType ();
478                                 static_data.DefineType ();
479
480                                 AddCompilerGeneratedClass (static_data);
481                         }
482
483                         return static_data.DefineInitializedData (data, loc);
484                 }
485
486                 protected override bool AddMemberType (TypeContainer ds)
487                 {
488                         if (!AddToContainer (ds, ds.Name))
489                                 return false;
490                         ds.NamespaceEntry.NS.AddType (ds.Definition);
491                         return true;
492                 }
493
494                 protected override void RemoveMemberType (DeclSpace ds)
495                 {
496                         ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
497                         base.RemoveMemberType (ds);
498                 }
499
500                 /// <summary>
501                 /// It is called very early therefore can resolve only predefined attributes
502                 /// </summary>
503                 void ResolveGlobalAttributes ()
504                 {
505                         if (OptAttributes == null)
506                                 return;
507
508                         if (!OptAttributes.CheckTargets ())
509                                 return;
510
511                         // FIXME: Define is wrong as the type may not exist yet
512                         var DefaultCharSet_attr = new PredefinedAttribute (this, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
513                         DefaultCharSet_attr.Define ();
514                         Attribute a = ResolveModuleAttribute (DefaultCharSet_attr);
515                         if (a != null) {
516                                 has_default_charset = true;
517                                 DefaultCharSet = a.GetCharSetValue ();
518                                 switch (DefaultCharSet) {
519                                 case CharSet.Ansi:
520                                 case CharSet.None:
521                                         break;
522                                 case CharSet.Auto:
523                                         DefaultCharSetType = TypeAttributes.AutoClass;
524                                         break;
525                                 case CharSet.Unicode:
526                                         DefaultCharSetType = TypeAttributes.UnicodeClass;
527                                         break;
528                                 default:
529                                         Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid", 
530                                                 DefaultCharSet_attr.GetSignatureForError ());
531                                         break;
532                                 }
533                         }
534                 }
535
536                 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
537                 {
538                         Attribute a = OptAttributes.Search ("assembly", a_type);
539                         if (a != null) {
540                                 a.Resolve ();
541                         }
542                         return a;
543                 }
544
545                 Attribute ResolveModuleAttribute (PredefinedAttribute a_type)
546                 {
547                         Attribute a = OptAttributes.Search ("module", a_type);
548                         if (a != null) {
549                                 a.Resolve ();
550                         }
551                         return a;
552                 }
553
554                 public void SetDeclaringAssembly (AssemblyDefinition assembly)
555                 {
556                         // TODO: This setter is quite ugly but I have not found a way around it yet
557                         this.assembly = assembly;
558                 }
559         }
560
561         class RootDeclSpace : TypeContainer {
562                 public RootDeclSpace (NamespaceEntry ns)
563                         : base (ns, null, MemberName.Null, null, 0)
564                 {
565                         PartialContainer = RootContext.ToplevelTypes;
566                 }
567
568                 public override AttributeTargets AttributeTargets {
569                         get { throw new InternalErrorException ("should not be called"); }
570                 }
571
572                 public override CompilerContext Compiler {
573                         get {
574                                 return PartialContainer.Compiler;
575                         }
576                 }
577
578                 public override string DocCommentHeader {
579                         get { throw new InternalErrorException ("should not be called"); }
580                 }
581
582                 public override void DefineType ()
583                 {
584                         throw new InternalErrorException ("should not be called");
585                 }
586
587                 public override ModuleContainer Module {
588                         get {
589                                 return PartialContainer.Module;
590                         }
591                 }
592
593                 public override bool IsClsComplianceRequired ()
594                 {
595                         return PartialContainer.IsClsComplianceRequired ();
596                 }
597
598                 public override FullNamedExpression LookupNamespaceAlias (string name)
599                 {
600                         return NamespaceEntry.LookupNamespaceAlias (name);
601                 }
602         }
603 }