2 // rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
\r
4 // Author: Miguel de Icaza (miguel@ximian.com)
\r
5 // Ravi Pratap (ravi@ximian.com)
\r
7 // Licensed under the terms of the GNU GPL
\r
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
\r
12 using System.Collections;
\r
13 using System.Reflection;
\r
14 using System.Reflection.Emit;
\r
15 using System.Diagnostics;
\r
17 namespace Mono.CSharp {
\r
19 public class RootContext {
\r
22 // Contains the parsed tree
\r
27 // This hashtable contains all of the #definitions across the source code
\r
28 // it is used by the ConditionalAttribute handler.
\r
30 public static Hashtable AllDefines = new Hashtable ();
\r
33 // The list of global attributes (those that target the assembly)
\r
35 static Hashtable global_attributes = new Hashtable ();
\r
38 // Whether we are being linked against the standard libraries.
\r
39 // This is only used to tell whether `System.Object' should
\r
40 // have a parent or not.
\r
42 public static bool StdLib = true;
\r
45 // This keeps track of the order in which classes were defined
\r
46 // so that we can poulate them in that order.
\r
48 // Order is important, because we need to be able to tell by
\r
49 // examining the parent's list of methods which ones are virtual
\r
50 // or abstract as well as the parent names (to implement new,
\r
53 static ArrayList type_container_resolve_order;
\r
54 static ArrayList interface_resolve_order;
\r
55 static ArrayList attribute_types;
\r
58 // Holds a reference to the Private Implementation Details
\r
61 static TypeBuilder impl_details_class;
\r
63 public static int WarningLevel = 2;
\r
68 static RootContext ()
\r
71 interface_resolve_order = new ArrayList ();
\r
72 type_container_resolve_order = new ArrayList ();
\r
75 static public Tree Tree {
\r
81 static public string MainClass;
\r
83 public static void RegisterOrder (Interface iface)
\r
85 interface_resolve_order.Add (iface);
\r
88 public static void RegisterOrder (TypeContainer tc)
\r
90 type_container_resolve_order.Add (tc);
\r
93 public static void RegisterAttribute (TypeContainer tc)
\r
95 if (attribute_types == null)
\r
96 attribute_types = new ArrayList ();
\r
98 attribute_types.Add (tc);
\r
102 // The default compiler checked state
\r
104 static public bool Checked = false;
\r
107 // Whether to allow Unsafe code
\r
109 static public bool Unsafe = false;
\r
111 // Root namespace name (implicit namespace)
\r
112 static public string RootNamespace = "";
\r
114 static string MakeFQN (string nsn, string name)
\r
116 string prefix = (nsn == "" ? "" : nsn + ".");
\r
118 return prefix + name;
\r
122 // This function is used to resolve the hierarchy tree.
\r
123 // It processes interfaces, structs and classes in that order.
\r
125 // It creates the TypeBuilder's as it processes the user defined
\r
128 static public void ResolveTree ()
\r
131 // Process the attribute types separately and before anything else
\r
133 if (attribute_types != null)
\r
134 foreach (TypeContainer tc in attribute_types)
\r
138 // Interfaces are processed next, as classes and
\r
139 // structs might inherit from an object or implement
\r
140 // a set of interfaces, we need to be able to tell
\r
141 // them appart by just using the TypeManager.
\r
143 TypeContainer root = Tree.Types;
\r
145 ArrayList ifaces = root.Interfaces;
\r
146 if (ifaces != null){
\r
147 foreach (Interface i in ifaces)
\r
152 foreach (TypeContainer tc in root.Types)
\r
155 if (root.Delegates != null)
\r
156 foreach (Delegate d in root.Delegates)
\r
159 if (root.Enums != null)
\r
160 foreach (Enum e in root.Enums)
\r
165 static void Error_TypeConflict (string name, Location loc)
\r
168 520, loc, "`" + name + "' conflicts with a predefined type");
\r
171 static void Error_TypeConflict (string name)
\r
174 520, "`" + name + "' conflicts with a predefined type");
\r
178 // Resolves a single class during the corlib bootstrap process
\r
180 static TypeBuilder BootstrapCorlib_ResolveClass (TypeContainer root, string name)
\r
182 object o = root.GetDefinition (name);
\r
184 Report.Error (518, "The predefined type `" + name + "' is not defined");
\r
188 if (!(o is Class)){
\r
189 if (o is DeclSpace){
\r
190 DeclSpace d = (DeclSpace) o;
\r
192 Error_TypeConflict (name, d.Location);
\r
194 Error_TypeConflict (name);
\r
199 return ((DeclSpace) o).DefineType ();
\r
203 // Resolves a struct during the corlib bootstrap process
\r
205 static void BootstrapCorlib_ResolveStruct (TypeContainer root, string name)
\r
207 object o = root.GetDefinition (name);
\r
209 Report.Error (518, "The predefined type `" + name + "' is not defined");
\r
213 if (!(o is Struct)){
\r
214 if (o is DeclSpace){
\r
215 DeclSpace d = (DeclSpace) o;
\r
217 Error_TypeConflict (name, d.Location);
\r
219 Error_TypeConflict (name);
\r
224 ((DeclSpace) o).DefineType ();
\r
228 // Resolves a struct during the corlib bootstrap process
\r
230 static void BootstrapCorlib_ResolveInterface (TypeContainer root, string name)
\r
232 object o = root.GetDefinition (name);
\r
234 Report.Error (518, "The predefined type `" + name + "' is not defined");
\r
238 if (!(o is Interface)){
\r
239 if (o is DeclSpace){
\r
240 DeclSpace d = (DeclSpace) o;
\r
242 Error_TypeConflict (name, d.Location);
\r
244 Error_TypeConflict (name);
\r
249 ((DeclSpace) o).DefineType ();
\r
253 // Resolves a delegate during the corlib bootstrap process
\r
255 static void BootstrapCorlib_ResolveDelegate (TypeContainer root, string name)
\r
257 object o = root.GetDefinition (name);
\r
259 Report.Error (518, "The predefined type `" + name + "' is not defined");
\r
260 Environment.Exit (0);
\r
263 if (!(o is Delegate)){
\r
264 Error_TypeConflict (name);
\r
268 ((DeclSpace) o).DefineType ();
\r
273 /// Resolves the core types in the compiler when compiling with --nostdlib
\r
275 static public void ResolveCore ()
\r
277 TypeContainer root = Tree.Types;
\r
279 TypeManager.object_type = BootstrapCorlib_ResolveClass (root, "System.Object");
\r
280 TypeManager.value_type = BootstrapCorlib_ResolveClass (root, "System.ValueType");
\r
281 TypeManager.attribute_type = BootstrapCorlib_ResolveClass (root, "System.Attribute");
\r
283 string [] interfaces_first_stage = {
\r
284 "System.IComparable", "System.ICloneable",
\r
285 "System.IConvertible",
\r
287 "System.Collections.IEnumerable",
\r
288 "System.Collections.ICollection",
\r
289 "System.Collections.IEnumerator",
\r
290 "System.Collections.IList",
\r
291 "System.IAsyncResult",
\r
292 "System.IDisposable",
\r
294 "System.Runtime.Serialization.ISerializable",
\r
296 "System.Reflection.IReflect",
\r
297 "System.Reflection.ICustomAttributeProvider"
\r
300 foreach (string iname in interfaces_first_stage)
\r
301 BootstrapCorlib_ResolveInterface (root, iname);
\r
304 // These are the base value types
\r
306 string [] structs_first_stage = {
\r
307 "System.Byte", "System.SByte",
\r
308 "System.Int16", "System.UInt16",
\r
309 "System.Int32", "System.UInt32",
\r
310 "System.Int64", "System.UInt64",
\r
313 foreach (string cname in structs_first_stage)
\r
314 BootstrapCorlib_ResolveStruct (root, cname);
\r
317 // Now, we can load the enumerations, after this point,
\r
318 // we can use enums.
\r
320 TypeManager.InitEnumUnderlyingTypes ();
\r
322 string [] structs_second_stage = {
\r
323 "System.Single", "System.Double",
\r
324 "System.Char", "System.Boolean",
\r
325 "System.Decimal", "System.Void",
\r
326 "System.RuntimeFieldHandle",
\r
327 "System.RuntimeTypeHandle",
\r
331 foreach (string cname in structs_second_stage)
\r
332 BootstrapCorlib_ResolveStruct (root, cname);
\r
335 // These are classes that depends on the core interfaces
\r
337 string [] classes_second_stage = {
\r
338 "System.Reflection.MemberInfo",
\r
340 "System.Exception",
\r
343 // These are not really important in the order, but they
\r
344 // are used by the compiler later on (typemanager/CoreLookupType-d)
\r
346 "System.Runtime.CompilerServices.RuntimeHelpers",
\r
347 "System.Reflection.DefaultMemberAttribute",
\r
348 "System.Threading.Monitor",
\r
350 "System.AttributeUsageAttribute",
\r
351 "System.Runtime.InteropServices.DllImportAttribute",
\r
352 "System.Runtime.CompilerServices.MethodImplAttribute",
\r
353 "System.Runtime.InteropServices.MarshalAsAttribute",
\r
354 "System.Diagnostics.ConditionalAttribute",
\r
355 "System.ObsoleteAttribute",
\r
356 "System.ParamArrayAttribute",
\r
357 "System.Security.UnverifiableCodeAttribute",
\r
358 "System.Runtime.CompilerServices.IndexerNameAttribute",
\r
361 // We must store them here before calling BootstrapCorlib_ResolveDelegate.
\r
362 TypeManager.string_type = BootstrapCorlib_ResolveClass (root, "System.String");
\r
363 TypeManager.enum_type = BootstrapCorlib_ResolveClass (root, "System.Enum");
\r
364 TypeManager.array_type = BootstrapCorlib_ResolveClass (root, "System.Array");
\r
365 TypeManager.multicast_delegate_type = BootstrapCorlib_ResolveClass (root, "System.MulticastDelegate");
\r
366 TypeManager.delegate_type = BootstrapCorlib_ResolveClass (root, "System.Delegate");
\r
368 foreach (string cname in classes_second_stage)
\r
369 BootstrapCorlib_ResolveClass (root, cname);
\r
371 BootstrapCorlib_ResolveDelegate (root, "System.AsyncCallback");
\r
375 // Closes all open types
\r
379 // We usually use TypeBuilder types. When we are done
\r
380 // creating the type (which will happen after we have added
\r
381 // methods, fields, etc) we need to "Define" them before we
\r
382 // can save the Assembly
\r
384 static public void CloseTypes ()
\r
386 TypeContainer root = Tree.Types;
\r
388 ArrayList ifaces = root.Interfaces;
\r
390 if (root.Enums != null)
\r
391 foreach (Enum en in root.Enums)
\r
394 if (attribute_types != null)
\r
395 foreach (TypeContainer tc in attribute_types)
\r
398 foreach (Interface iface in interface_resolve_order)
\r
399 iface.CloseType ();
\r
402 // We do this in two passes, first we close the structs,
\r
403 // then the classes, because it seems the code needs it this
\r
404 // way. If this is really what is going on, we should probably
\r
405 // make sure that we define the structs in order as well.
\r
407 foreach (TypeContainer tc in type_container_resolve_order){
\r
408 if (tc is Struct && tc.Parent == tree.Types){
\r
413 foreach (TypeContainer tc in type_container_resolve_order){
\r
414 if (!(tc is Struct && tc.Parent == tree.Types))
\r
418 if (root.Delegates != null)
\r
419 foreach (Delegate d in root.Delegates)
\r
424 // If we have a <PrivateImplementationDetails> class, close it
\r
426 if (impl_details_class != null){
\r
427 impl_details_class.CreateType ();
\r
432 // This idea is from Felix Arrese-Igor
\r
434 // Returns : the implicit parent of a composite namespace string
\r
435 // eg. Implicit parent of A.B is A
\r
437 static public string ImplicitParent (string ns)
\r
439 int i = ns.LastIndexOf (".");
\r
443 return ns.Substring (0, i);
\r
446 static Type NamespaceLookup (Namespace curr_ns, string name, Location loc)
\r
451 // Try in the current namespace and all its implicit parents
\r
453 for (string ns = curr_ns.Name; ns != null; ns = ImplicitParent (ns)) {
\r
454 t = TypeManager.LookupType (MakeFQN (ns, name));
\r
460 // It's possible that name already is fully qualified. So we do
\r
461 // a simple direct lookup without adding any namespace names
\r
463 t = TypeManager.LookupType (name);
\r
468 // Try the aliases in the current namespace
\r
470 string alias = curr_ns.LookupAlias (name);
\r
472 if (alias != null) {
\r
473 t = TypeManager.LookupType (alias);
\r
477 t = TypeManager.LookupType (MakeFQN (alias, name));
\r
482 for (Namespace ns = curr_ns; ns != null; ns = ns.Parent) {
\r
484 // Look in the namespace ns
\r
486 t = TypeManager.LookupType (MakeFQN (ns.Name, name));
\r
491 // Then try with the using clauses
\r
493 ArrayList using_list = ns.UsingTable;
\r
495 if (using_list == null)
\r
499 foreach (Namespace.UsingEntry ue in using_list) {
\r
500 match = TypeManager.LookupType (MakeFQN (ue.Name, name));
\r
501 if (match != null){
\r
503 DeclSpace.Error_AmbiguousTypeReference (loc, name, t, match);
\r
515 // Try with aliases
\r
517 string a = ns.LookupAlias (name);
\r
519 t = TypeManager.LookupType (a);
\r
523 t = TypeManager.LookupType (MakeFQN (a, name));
\r
533 // Public function used to locate types, this can only
\r
534 // be used after the ResolveTree function has been invoked.
\r
536 // Returns: Type or null if they type can not be found.
\r
538 // Come to think of it, this should be a DeclSpace
\r
540 static public Type LookupType (DeclSpace ds, string name, bool silent, Location loc)
\r
544 if (ds.Cache.Contains (name)){
\r
545 t = (Type) ds.Cache [name];
\r
550 // For the case the type we are looking for is nested within this one
\r
551 // or is in any base class
\r
553 DeclSpace containing_ds = ds;
\r
554 while (containing_ds != null){
\r
555 Type current_type = containing_ds.TypeBuilder;
\r
557 while (current_type != null) {
\r
561 t = TypeManager.LookupType (current_type.FullName + "." + name);
\r
563 ds.Cache [name] = t;
\r
567 current_type = current_type.BaseType;
\r
570 containing_ds = containing_ds.Parent;
\r
573 t = NamespaceLookup (ds.Namespace, name, loc);
\r
575 ds.Cache [name] = t;
\r
581 Report.Error (246, loc, "Cannot find type `"+name+"'");
\r
587 // This is the silent version of LookupType, you can use this
\r
588 // to `probe' for a type
\r
590 static public Type LookupType (TypeContainer tc, string name, Location loc)
\r
592 return LookupType (tc, name, true, loc);
\r
595 static public bool IsNamespace (string name)
\r
599 if (tree.Namespaces != null){
\r
600 ns = (Namespace) tree.Namespaces [name];
\r
609 static void Report1530 (Location loc)
\r
611 Report.Error (1530, loc, "Keyword new not allowed for namespace elements");
\r
614 static public void PopulateCoreType (TypeContainer root, string name)
\r
616 DeclSpace ds = (DeclSpace) root.GetDefinition (name);
\r
618 ds.DefineMembers (root);
\r
622 static public void BootCorlib_PopulateCoreTypes ()
\r
624 TypeContainer root = tree.Types;
\r
626 PopulateCoreType (root, "System.Object");
\r
627 PopulateCoreType (root, "System.ValueType");
\r
628 PopulateCoreType (root, "System.Attribute");
\r
632 // Populates the structs and classes with fields and methods
\r
635 // This is invoked after all interfaces, structs and classes
\r
636 // have been defined through `ResolveTree'
\r
637 static public void PopulateTypes ()
\r
639 TypeContainer root = Tree.Types;
\r
641 if (attribute_types != null)
\r
642 foreach (TypeContainer tc in attribute_types)
\r
643 tc.DefineMembers (root);
\r
645 if (interface_resolve_order != null){
\r
646 foreach (Interface iface in interface_resolve_order)
\r
647 if ((iface.ModFlags & Modifiers.NEW) == 0)
\r
648 iface.DefineMembers (root);
\r
650 Report1530 (iface.Location);
\r
654 if (type_container_resolve_order != null){
\r
655 foreach (TypeContainer tc in type_container_resolve_order) {
\r
656 // When compiling corlib, these types have already been
\r
657 // populated from BootCorlib_PopulateCoreTypes ().
\r
658 if (!RootContext.StdLib &&
\r
659 ((tc.Name == "System.Object") ||
\r
660 (tc.Name == "System.Attribute") ||
\r
661 (tc.Name == "System.ValueType")))
\r
664 if ((tc.ModFlags & Modifiers.NEW) == 0)
\r
665 tc.DefineMembers (root);
\r
667 Report1530 (tc.Location);
\r
671 ArrayList delegates = root.Delegates;
\r
672 if (delegates != null){
\r
673 foreach (Delegate d in delegates)
\r
674 if ((d.ModFlags & Modifiers.NEW) == 0)
\r
675 d.DefineMembers (root);
\r
677 Report1530 (d.Location);
\r
680 ArrayList enums = root.Enums;
\r
681 if (enums != null){
\r
682 foreach (Enum en in enums)
\r
683 if ((en.ModFlags & Modifiers.NEW) == 0)
\r
684 en.DefineMembers (root);
\r
686 Report1530 (en.Location);
\r
690 static public void DefineTypes ()
\r
692 TypeContainer root = Tree.Types;
\r
694 if (attribute_types != null)
\r
695 foreach (TypeContainer tc in attribute_types)
\r
698 if (interface_resolve_order != null){
\r
699 foreach (Interface iface in interface_resolve_order)
\r
700 if ((iface.ModFlags & Modifiers.NEW) == 0)
\r
701 iface.Define (root);
\r
705 if (type_container_resolve_order != null){
\r
706 foreach (TypeContainer tc in type_container_resolve_order) {
\r
707 // When compiling corlib, these types have already been
\r
708 // populated from BootCorlib_PopulateCoreTypes ().
\r
709 if (!RootContext.StdLib &&
\r
710 ((tc.Name == "System.Object") ||
\r
711 (tc.Name == "System.Attribute") ||
\r
712 (tc.Name == "System.ValueType")))
\r
715 if ((tc.ModFlags & Modifiers.NEW) == 0)
\r
720 ArrayList delegates = root.Delegates;
\r
721 if (delegates != null){
\r
722 foreach (Delegate d in delegates)
\r
723 if ((d.ModFlags & Modifiers.NEW) == 0)
\r
727 ArrayList enums = root.Enums;
\r
728 if (enums != null){
\r
729 foreach (Enum en in enums)
\r
730 if ((en.ModFlags & Modifiers.NEW) == 0)
\r
735 static public void EmitCode ()
\r
738 // Because of the strange way in which we do things, global
\r
739 // attributes must be processed first.
\r
741 if (global_attributes.Count > 0){
\r
742 AssemblyBuilder ab = CodeGen.AssemblyBuilder;
\r
743 TypeContainer dummy = new TypeContainer (null, "", new Location (-1, 0));
\r
744 EmitContext temp_ec = new EmitContext (
\r
745 dummy, Mono.CSharp.Location.Null, null, null, 0, false);
\r
747 foreach (DictionaryEntry de in global_attributes){
\r
748 Namespace ns = (Namespace) de.Key;
\r
749 Attributes attrs = (Attributes) de.Value;
\r
751 dummy.Namespace = ns;
\r
752 Attribute.ApplyAttributes (temp_ec, ab, ab, attrs, attrs.Location);
\r
756 if (attribute_types != null)
\r
757 foreach (TypeContainer tc in attribute_types)
\r
760 if (type_container_resolve_order != null) {
\r
761 foreach (TypeContainer tc in type_container_resolve_order)
\r
762 tc.EmitConstants ();
\r
764 foreach (TypeContainer tc in type_container_resolve_order)
\r
769 if (TypeManager.unverifiable_code_ctor == null) {
\r
770 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
\r
774 CustomAttributeBuilder cb = new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]);
\r
775 CodeGen.ModuleBuilder.SetCustomAttribute (cb);
\r
780 // Public Field, used to track which method is the public entry
\r
783 static public MethodInfo EntryPoint;
\r
786 // Track the location of the entry point.
\r
788 static public Location EntryPointLocation;
\r
791 // These are used to generate unique names on the structs and fields.
\r
793 static int field_count;
\r
796 // Makes an initialized struct, returns the field builder that
\r
797 // references the data. Thanks go to Sergey Chaban for researching
\r
798 // how to do this. And coming up with a shorter mechanism than I
\r
799 // was able to figure out.
\r
801 // This works but makes an implicit public struct $ArrayType$SIZE and
\r
802 // makes the fields point to it. We could get more control if we did
\r
805 // 1. DefineNestedType on the impl_details_class with our struct.
\r
807 // 2. Define the field on the impl_details_class
\r
809 static public FieldBuilder MakeStaticData (byte [] data)
\r
812 int size = data.Length;
\r
814 if (impl_details_class == null)
\r
815 impl_details_class = CodeGen.ModuleBuilder.DefineType (
\r
816 "<PrivateImplementationDetails>", TypeAttributes.NotPublic, TypeManager.object_type);
\r
818 fb = impl_details_class.DefineInitializedData (
\r
819 "$$field-" + (field_count++), data,
\r
820 FieldAttributes.Static | FieldAttributes.Assembly);
\r
826 // Adds a global attribute that was declared in `container',
\r
827 // the attribute is in `attr', and it was defined at `loc'
\r
829 static public void AddGlobalAttribute (TypeContainer container,
\r
830 AttributeSection attr, Location loc)
\r
832 Namespace ns = container.Namespace;
\r
833 Attributes a = (Attributes) global_attributes [ns];
\r
836 global_attributes [ns] = new Attributes (attr, loc);
\r
838 a.AddAttribute (attr);
\r
842 // Adds a global attribute that was declared in `container',
\r
843 // the attribute is in `attr', and it was defined at `loc'
\r
845 static public void AddGlobalAttributeSection (TypeContainer container, AttributeSection attr)
\r
847 Namespace ns = container.Namespace;
\r
848 Attributes a = (Attributes) global_attributes [ns];
\r
851 global_attributes [ns] = new Attributes (attr, Location.Null);
\r
853 a.AddAttributeSection (attr);
\r