2002-05-31 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
[mono.git] / mcs / mbas / rootcontext.cs
1 //
2 // rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
3 //
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 //         Ravi Pratap     (ravi@ximian.com)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10
11 using System;
12 using System.Collections;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Diagnostics;
16
17 namespace Mono.CSharp {
18
19         public class RootContext {
20
21                 //
22                 // Contains the parsed tree
23                 //
24                 static Tree tree;
25
26                 static public bool Optimize;
27
28                 //
29                 // If this value is `true', then calls to the Trace class are disabled
30                 //
31                 static public bool DisableTrace = true;
32
33                 //
34                 // If this value is `true', then calls to the Debug class are disabled
35                 //
36                 static public bool DisableDebug = true;
37                 
38                 //
39                 // The list of global attributes (those that target the assembly)
40                 //
41                 static Hashtable global_attributes = new Hashtable ();
42                 
43                 //
44                 // Whether we are being linked against the standard libraries.
45                 // This is only used to tell whether `System.Object' should
46                 // have a parent or not.
47                 //
48                 public static bool StdLib = true;
49
50                 //
51                 // This keeps track of the order in which classes were defined
52                 // so that we can poulate them in that order.
53                 //
54                 // Order is important, because we need to be able to tell by
55                 // examining the parent's list of methods which ones are virtual
56                 // or abstract as well as the parent names (to implement new, 
57                 // override).
58                 //
59                 static ArrayList type_container_resolve_order;
60                 static ArrayList interface_resolve_order;
61                 static ArrayList attribute_types;
62
63                 //
64                 // Holds a reference to the Private Implementation Details
65                 // class.
66                 //
67                 static TypeBuilder impl_details_class;
68
69                 public static int WarningLevel = 2;
70                 
71                 //
72                 // Constructor
73                 //
74                 static RootContext ()
75                 {
76                         tree = new Tree ();
77                         interface_resolve_order = new ArrayList ();
78                         type_container_resolve_order = new ArrayList ();
79                 }
80
81                 static public Tree Tree {
82                         get {
83                                 return tree;
84                         }
85                 }
86
87                 static public string MainClass;
88                 
89                 public static void RegisterOrder (Interface iface)
90                 {
91                         interface_resolve_order.Add (iface);
92                 }
93                 
94                 public static void RegisterOrder (TypeContainer tc)
95                 {
96                         type_container_resolve_order.Add (tc);
97                 }
98
99                 public static void RegisterAttribute (TypeContainer tc)
100                 {
101                         if (attribute_types == null)
102                                 attribute_types = new ArrayList ();
103                         
104                         attribute_types.Add (tc);
105                 }
106                 
107                 // 
108                 // The default compiler checked state
109                 //
110                 static public bool Checked = false;
111
112                 //
113                 // Whether to allow Unsafe code
114                 //
115                 static public bool Unsafe = false;
116                 
117                 static string MakeFQN (string nsn, string name)
118                 {
119                         string prefix = (nsn == "" ? "" : nsn + ".");
120
121                         return prefix + name;
122                 }
123                        
124                 // <remarks>
125                 //   This function is used to resolve the hierarchy tree.
126                 //   It processes interfaces, structs and classes in that order.
127                 //
128                 //   It creates the TypeBuilder's as it processes the user defined
129                 //   types.  
130                 // </remarks>
131                 static public void ResolveTree ()
132                 {
133                         //
134                         // Process the attribute types separately and before anything else
135                         //
136                         if (attribute_types != null)
137                                 foreach (TypeContainer tc in attribute_types)
138                                         tc.DefineType ();
139                         
140                         //
141                         // Interfaces are processed next, as classes and
142                         // structs might inherit from an object or implement
143                         // a set of interfaces, we need to be able to tell
144                         // them appart by just using the TypeManager.
145                         //
146                         TypeContainer root = Tree.Types;
147
148                         ArrayList ifaces = root.Interfaces;
149                         if (ifaces != null){
150                                 foreach (Interface i in ifaces) 
151                                         i.DefineType ();
152                         }
153
154                         
155                         foreach (TypeContainer tc in root.Types) 
156                                 tc.DefineType ();
157
158                         if (root.Delegates != null)
159                                 foreach (Delegate d in root.Delegates) 
160                                         d.DefineType ();
161
162                         if (root.Enums != null)
163                                 foreach (Enum e in root.Enums)
164                                         e.DefineType ();
165                         
166                 }
167
168                 static void Error_TypeConflict (string name, Location loc)
169                 {
170                         Report.Error (
171                                 520, loc, "`" + name + "' conflicts with a predefined type");
172                 }
173
174                 static void Error_TypeConflict (string name)
175                 {
176                         Report.Error (
177                                 520, "`" + name + "' conflicts with a predefined type");
178                 }
179
180                 //
181                 // Resolves a single class during the corlib bootstrap process
182                 //
183                 static TypeBuilder BootstrapCorlib_ResolveClass (TypeContainer root, string name)
184                 {
185                         object o = root.GetDefinition (name);
186                         if (o == null){
187                                 Report.Error (518, "The predefined type `" + name + "' is not defined");
188                                 return null;
189                         }
190
191                         if (!(o is Class)){
192                                 if (o is DeclSpace){
193                                         DeclSpace d = (DeclSpace) o;
194
195                                         Error_TypeConflict (name, d.Location);
196                                 } else
197                                         Error_TypeConflict (name);
198
199                                 return null;
200                         }
201
202                         return ((DeclSpace) o).DefineType ();
203                 }
204
205                 //
206                 // Resolves a struct during the corlib bootstrap process
207                 //
208                 static void BootstrapCorlib_ResolveStruct (TypeContainer root, string name)
209                 {
210                         object o = root.GetDefinition (name);
211                         if (o == null){
212                                 Report.Error (518, "The predefined type `" + name + "' is not defined");
213                                 return;
214                         }
215
216                         if (!(o is Struct)){
217                                 if (o is DeclSpace){
218                                         DeclSpace d = (DeclSpace) o;
219
220                                         Error_TypeConflict (name, d.Location);
221                                 } else
222                                         Error_TypeConflict (name);
223
224                                 return;
225                         }
226
227                         ((DeclSpace) o).DefineType ();
228                 }
229
230                 //
231                 // Resolves a struct during the corlib bootstrap process
232                 //
233                 static void BootstrapCorlib_ResolveInterface (TypeContainer root, string name)
234                 {
235                         object o = root.GetDefinition (name);
236                         if (o == null){
237                                 Report.Error (518, "The predefined type `" + name + "' is not defined");
238                                 return;
239                         }
240
241                         if (!(o is Interface)){
242                                 if (o is DeclSpace){
243                                         DeclSpace d = (DeclSpace) o;
244
245                                         Error_TypeConflict (name, d.Location);
246                                 } else
247                                         Error_TypeConflict (name);
248
249                                 return;
250                         }
251
252                         ((DeclSpace) o).DefineType ();
253                 }
254
255                 //
256                 // Resolves a delegate during the corlib bootstrap process
257                 //
258                 static void BootstrapCorlib_ResolveDelegate (TypeContainer root, string name)
259                 {
260                         object o = root.GetDefinition (name);
261                         if (o == null){
262                                 Report.Error (518, "The predefined type `" + name + "' is not defined");
263                                 Environment.Exit (0);
264                         }
265
266                         if (!(o is Delegate)){
267                                 Error_TypeConflict (name);
268                                 return;
269                         }
270
271                         ((DeclSpace) o).DefineType ();
272                 }
273                 
274
275                 /// <summary>
276                 ///    Resolves the core types in the compiler when compiling with --nostdlib
277                 /// </summary>
278                 static public void ResolveCore ()
279                 {
280                         TypeContainer root = Tree.Types;
281
282                         TypeManager.object_type = BootstrapCorlib_ResolveClass (root, "System.Object");
283                         TypeManager.value_type = BootstrapCorlib_ResolveClass (root, "System.ValueType");
284                         TypeManager.attribute_type = BootstrapCorlib_ResolveClass (root, "System.Attribute");
285                         
286                         string [] interfaces_first_stage = {
287                                 "System.IComparable", "System.ICloneable",
288                                 "System.IConvertible",
289                                 
290                                 "System.Collections.IEnumerable",
291                                 "System.Collections.ICollection",
292                                 "System.Collections.IEnumerator",
293                                 "System.Collections.IList", 
294                                 "System.IAsyncResult",
295                                 "System.IDisposable",
296                                 
297                                 "System.Runtime.Serialization.ISerializable",
298
299                                 "System.Reflection.IReflect",
300                                 "System.Reflection.ICustomAttributeProvider"
301                         };
302
303                         foreach (string iname in interfaces_first_stage)
304                                 BootstrapCorlib_ResolveInterface (root, iname);
305
306                         //
307                         // These are the base value types
308                         //
309                         string [] structs_first_stage = {
310                                 "System.Byte",    "System.SByte",
311                                 "System.Int16",   "System.UInt16",
312                                 "System.Int32",   "System.UInt32",
313                                 "System.Int64",   "System.UInt64",
314                         };
315
316                         foreach (string cname in structs_first_stage)
317                                 BootstrapCorlib_ResolveStruct (root, cname);
318
319                         //
320                         // Now, we can load the enumerations, after this point,
321                         // we can use enums.
322                         //
323                         TypeManager.InitEnumUnderlyingTypes ();
324
325                         string [] structs_second_stage = {
326                                 "System.Single",  "System.Double",
327                                 "System.Char",    "System.Boolean",
328                                 "System.Decimal", "System.Void",
329                                 "System.RuntimeFieldHandle",
330                                 "System.RuntimeTypeHandle",
331                                 "System.IntPtr"
332                         };
333                         
334                         foreach (string cname in structs_second_stage)
335                                 BootstrapCorlib_ResolveStruct (root, cname);
336                         
337                         //
338                         // These are classes that depends on the core interfaces
339                         //
340                         string [] classes_second_stage = {
341                                 "System.String", "System.Enum",
342                                 "System.Array",  "System.MulticastDelegate",
343                                 "System.Delegate",
344
345                                 "System.Reflection.MemberInfo",
346                                 "System.Type",
347
348                                 //
349                                 // These are not really important in the order, but they
350                                 // are used by the compiler later on (typemanager/CoreLookupType-d)
351                                 //
352                                 "System.Runtime.CompilerServices.RuntimeHelpers",
353                                 "System.Reflection.DefaultMemberAttribute",
354                                 "System.Threading.Monitor",
355                                 
356                                 "System.AttributeUsageAttribute",
357                                 "System.Runtime.InteropServices.DllImportAttribute",
358                                 "System.Runtime.CompilerServices.MethodImplAttribute",
359                                 "System.Runtime.InteropServices.MarshalAsAttribute",
360                                 "System.ParamArrayAttribute",
361                                 "System.Security.UnverifiableCodeAttribute",
362                         };
363                         
364                         foreach (string cname in classes_second_stage)
365                                 BootstrapCorlib_ResolveClass (root, cname);
366
367                         BootstrapCorlib_ResolveDelegate (root, "System.AsyncCallback");
368                 }
369                         
370                 // <summary>
371                 //   Closes all open types
372                 // </summary>
373                 //
374                 // <remarks>
375                 //   We usually use TypeBuilder types.  When we are done
376                 //   creating the type (which will happen after we have added
377                 //   methods, fields, etc) we need to "Define" them before we
378                 //   can save the Assembly
379                 // </remarks>
380                 static public void CloseTypes ()
381                 {
382                         TypeContainer root = Tree.Types;
383                         
384                         ArrayList ifaces = root.Interfaces;
385
386                         if (root.Enums != null)
387                                 foreach (Enum en in root.Enums)
388                                         en.CloseType ();
389
390                         if (attribute_types != null)
391                                 foreach (TypeContainer tc in attribute_types)
392                                         tc.CloseType ();
393                         
394                         foreach (Interface iface in interface_resolve_order)
395                                 iface.CloseType ();
396
397                         //
398                         // We do this in two passes, first we close the structs,
399                         // then the classes, because it seems the code needs it this
400                         // way.  If this is really what is going on, we should probably
401                         // make sure that we define the structs in order as well.
402                         //
403                         foreach (TypeContainer tc in type_container_resolve_order){
404                                 if (tc is Struct && tc.Parent == tree.Types){
405                                         tc.CloseType ();
406                                 }
407                         }
408
409                         foreach (TypeContainer tc in type_container_resolve_order){
410                                 if (!(tc is Struct && tc.Parent == tree.Types))
411                                         tc.CloseType ();                                        
412                         }
413                         
414                         if (root.Delegates != null)
415                                 foreach (Delegate d in root.Delegates)
416                                         d.CloseDelegate ();
417
418
419                         //
420                         // If we have a <PrivateImplementationDetails> class, close it
421                         //
422                         if (impl_details_class != null){
423                                 impl_details_class.CreateType ();
424                         }
425                 }
426
427                 //
428                 // This idea is from Felix Arrese-Igor
429                 //
430                 // Returns : the implicit parent of a composite namespace string
431                 //   eg. Implicit parent of A.B is A
432                 //
433                 static public string ImplicitParent (string ns)
434                 {
435                         int i = ns.LastIndexOf (".");
436                         if (i < 0)
437                                 return null;
438                         
439                         return ns.Substring (0, i);
440                 }
441
442                 static Type NamespaceLookup (Namespace curr_ns, string name)
443                 {
444                         Type t;
445                         
446                         //
447                         // Try in the current namespace and all its implicit parents
448                         //
449                         for (string ns = curr_ns.Name; ns != null; ns = ImplicitParent (ns)) {
450                                 t = TypeManager.LookupType (MakeFQN (ns, name));
451                                 if (t != null)
452                                         return t;
453                         }
454                         
455                         //
456                         // It's possible that name already is fully qualified. So we do
457                         // a simple direct lookup without adding any namespace names
458                         //
459                         t = TypeManager.LookupType (name); 
460                         if (t != null)
461                                 return t;
462
463                         //
464                         // Try the aliases in the current namespace
465                         //
466                         string alias = curr_ns.LookupAlias (name);
467
468                         if (alias != null) {
469                                 t = TypeManager.LookupType (alias);
470                                 if (t != null)
471                                         return t;
472
473                                 t = TypeManager.LookupType (MakeFQN (alias, name));
474                                 if (t != null)
475                                         return t;
476                         }
477                         
478                         for (Namespace ns = curr_ns; ns != null; ns = ns.Parent) {
479                                 //
480                                 // Look in the namespace ns
481                                 //
482                                 t = TypeManager.LookupType (MakeFQN (ns.Name, name));
483                                 if (t != null)
484                                         return t;
485                                 
486                                 //
487                                 // Then try with the using clauses
488                                 //
489                                 ArrayList using_list = ns.UsingTable;
490
491                                 if (using_list == null)
492                                         continue;
493
494                                 foreach (string n in using_list) {
495                                         t = TypeManager.LookupType (MakeFQN (n, name));
496                                         if (t != null)
497                                                 return t;
498                                 }
499
500                                 //
501                                 // Try with aliases
502                                 //
503                                 string a = ns.LookupAlias (name);
504                                 if (a != null) {
505                                         t = TypeManager.LookupType (a);
506                                         if (t != null)
507                                                 return t;
508
509                                         t = TypeManager.LookupType (MakeFQN (a, name));
510                                         if (t != null)
511                                                 return t;
512                                 }
513                         }
514
515                         return null;
516                 }
517                 
518                 //
519                 // Public function used to locate types, this can only
520                 // be used after the ResolveTree function has been invoked.
521                 //
522                 // Returns: Type or null if they type can not be found.
523                 //
524                 // Come to think of it, this should be a DeclSpace
525                 //
526                 static public Type LookupType (DeclSpace ds, string name, bool silent, Location loc)
527                 {
528                         Type t;
529
530                         if (ds.Cache.Contains (name)){
531                                 t = (Type) ds.Cache [name];
532                                 if (t != null)
533                                         return t;
534                         } else {
535                                 //
536                                 // For the case the type we are looking for is nested within this one
537                                 // or is in any base class
538                                 //
539                                 DeclSpace containing_ds = ds;
540                                 while (containing_ds != null){
541                                         Type current_type = containing_ds.TypeBuilder;
542                                         
543                                         while (current_type != null) {
544                                                 //
545                                                 // nested class
546                                                 //
547                                                 t = TypeManager.LookupType (current_type.FullName + "+" + name);
548                                                 if (t != null){
549                                                         ds.Cache [name] = t;
550                                                         return t;
551                                                 }
552                                                 
553                                                 current_type = current_type.BaseType;
554                                         }
555                                         
556                                         containing_ds = containing_ds.Parent;
557                                 }
558                                 
559                                 t = NamespaceLookup (ds.Namespace, name);
560                                 if (t != null){
561                                         ds.Cache [name] = t;
562                                         return t;
563                                 }
564                         }
565
566                         if (!silent)
567                                 Report.Error (246, loc, "Cannot find type `"+name+"'");
568                         
569                         return null;
570                 }
571
572                 // <summary>
573                 //   This is the silent version of LookupType, you can use this
574                 //   to `probe' for a type
575                 // </summary>
576                 static public Type LookupType (TypeContainer tc, string name, Location loc)
577                 {
578                         return LookupType (tc, name, true, loc);
579                 }
580
581                 static public bool IsNamespace (string name)
582                 {
583                         Namespace ns;
584
585                         if (tree.Namespaces != null){
586                                 ns = (Namespace) tree.Namespaces [name];
587
588                                 if (ns != null)
589                                         return true;
590                         }
591
592                         return false;
593                 }
594
595                 static void Report1530 (Location loc)
596                 {
597                         Report.Error (1530, loc, "Keyword new not allowed for namespace elements");
598                 }
599                 
600                 static public void PopulateCoreType (TypeContainer root, string name)
601                 {
602                         DeclSpace ds = (DeclSpace) root.GetDefinition (name);
603
604                         ds.Define (root);
605                 }
606                 
607                 static public void BootCorlib_PopulateCoreTypes ()
608                 {
609                         TypeContainer root = tree.Types;
610
611                         PopulateCoreType (root, "System.Object");
612                         PopulateCoreType (root, "System.ValueType");
613                         PopulateCoreType (root, "System.Attribute");
614                 }
615                 
616                 // <summary>
617                 //   Populates the structs and classes with fields and methods
618                 // </summary>
619                 //
620                 // This is invoked after all interfaces, structs and classes
621                 // have been defined through `ResolveTree' 
622                 static public void PopulateTypes ()
623                 {
624                         TypeContainer root = Tree.Types;
625
626                         if (attribute_types != null)
627                                 foreach (TypeContainer tc in attribute_types)
628                                         tc.Define (root);
629                         
630                         if (interface_resolve_order != null){
631                                 foreach (Interface iface in interface_resolve_order)
632                                         if ((iface.ModFlags & Modifiers.NEW) == 0)
633                                                 iface.Define (root);
634                                         else
635                                                 Report1530 (iface.Location);
636                         }
637
638
639                         if (type_container_resolve_order != null){
640                                 foreach (TypeContainer tc in type_container_resolve_order)
641                                         if ((tc.ModFlags & Modifiers.NEW) == 0)
642                                                 tc.Define (root);
643                                         else
644                                                 Report1530 (tc.Location);
645                         }
646
647                         ArrayList delegates = root.Delegates;
648                         if (delegates != null){
649                                 foreach (Delegate d in delegates)
650                                         if ((d.ModFlags & Modifiers.NEW) == 0)
651                                                 d.Define (root);
652                                         else
653                                                 Report1530 (d.Location);
654                         }
655
656                         ArrayList enums = root.Enums;
657                         if (enums != null){
658                                 foreach (Enum en in enums)
659                                         if ((en.ModFlags & Modifiers.NEW) == 0)
660                                                 en.Define (root);
661                                         else
662                                                 Report1530 (en.Location);
663                         }
664                 }
665
666                 static public void EmitCode ()
667                 {
668                         //
669                         // Because of the strange way in which we do things, global
670                         // attributes must be processed first.
671                         //
672                         if (global_attributes.Count > 0){
673                                 AssemblyBuilder ab = CodeGen.AssemblyBuilder;
674                                 TypeContainer dummy = new TypeContainer (null, "", new Location (-1));
675                                 EmitContext temp_ec = new EmitContext (
676                                         dummy, Mono.CSharp.Location.Null, null, null, 0, false);
677                         
678                                 foreach (DictionaryEntry de in global_attributes){
679                                         Namespace ns = (Namespace) de.Key;
680                                         Attributes attrs = (Attributes) de.Value;
681                                         
682                                         dummy.Namespace = ns;
683                                         Attribute.ApplyAttributes (temp_ec, ab, ab, attrs, attrs.Location);
684                                 }
685                         }
686                         
687                         if (attribute_types != null)
688                                 foreach (TypeContainer tc in attribute_types)
689                                         tc.Emit ();
690                         
691                         if (type_container_resolve_order != null) {
692                                 foreach (TypeContainer tc in type_container_resolve_order)
693                                         tc.EmitConstants ();
694                                 
695                                 foreach (TypeContainer tc in type_container_resolve_order)
696                                         tc.Emit ();
697                         }
698                         
699                         if (Unsafe) {
700                                 ConstructorInfo ci = TypeManager.unverifiable_code_type.GetConstructor (new Type [0]);
701                                         
702                                 if (ci == null) {
703                                         Console.WriteLine ("Internal error !");
704                                         return;
705                                 }
706                                 
707                                 CustomAttributeBuilder cb = new CustomAttributeBuilder (ci, new object [0]);
708                                 CodeGen.ModuleBuilder.SetCustomAttribute (cb);
709                         }
710                 }
711                 
712                 //
713                 // Public Field, used to track which method is the public entry
714                 // point.
715                 //
716                 static public MethodInfo EntryPoint;
717
718                 //
719                 // Track the location of the entry point.
720                 //
721                 static public Location EntryPointLocation;
722
723                 //
724                 // These are used to generate unique names on the structs and fields.
725                 //
726                 static int field_count;
727                 
728                 //
729                 // Makes an initialized struct, returns the field builder that
730                 // references the data.  Thanks go to Sergey Chaban for researching
731                 // how to do this.  And coming up with a shorter mechanism than I
732                 // was able to figure out.
733                 //
734                 // This works but makes an implicit public struct $ArrayType$SIZE and
735                 // makes the fields point to it.  We could get more control if we did
736                 // use instead:
737                 //
738                 // 1. DefineNestedType on the impl_details_class with our struct.
739                 //
740                 // 2. Define the field on the impl_details_class
741                 //
742                 static public FieldBuilder MakeStaticData (byte [] data)
743                 {
744                         FieldBuilder fb;
745                         int size = data.Length;
746                         
747                         if (impl_details_class == null)
748                                 impl_details_class = CodeGen.ModuleBuilder.DefineType (
749                                         "<PrivateImplementationDetails>", TypeAttributes.NotPublic);
750
751                         fb = impl_details_class.DefineInitializedData (
752                                 "$$field-" + (field_count++), data,
753                                 FieldAttributes.Static | FieldAttributes.Assembly);
754                         
755                         return fb;
756                 }
757
758                 //
759                 // Adds a global attribute that was declared in `container', 
760                 // the attribute is in `attr', and it was defined at `loc'
761                 //
762                 static public void AddGlobalAttribute (TypeContainer container,
763                                                        AttributeSection attr, Location loc)
764                 {
765                         Namespace ns = container.Namespace;
766                         Attributes a = (Attributes) global_attributes [ns];
767
768                         if (a == null)
769                                 global_attributes [ns] = new Attributes (attr, loc);
770                         else
771                                 a.AddAttribute (attr);
772                 }
773         }
774 }
775               
776