/* * Copyright (c) 2003-2008 The University of Wroclaw. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the University may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using Nemerle; using Nemerle.Utility; using Nemerle.Collections; using Nemerle.Compiler.SolverMacros; using Nemerle.Compiler.Typedtree; using PT = Nemerle.Compiler.Parsetree; using SCG = System.Collections.Generic; namespace Nemerle.Compiler { [Nemerle.Compiler.SupportRelocation] public partial class TypeBuilder : TypeInfo { type Subinfo = Map [TypeInfo, TypeInfo * list [MType]]; mutable tydecl : TypeDeclaration; before_finalization : Queue [void -> void] = Queue (); before_finalization2 : Queue [void -> void] = Queue (); enclosing_type : TypeBuilder; internal mutable parent_type : MType.Class; internal mutable forced_typarms : list [StaticTyVar]; internal mutable reflection_inheritance_emitted : bool; internal mutable is_lambda : bool; mutable t_implements : list [MType.Class]; [Accessor (DeclaredNestedTypes)] mutable contained_types : list [TypeBuilder] = []; mutable variant_options : list [TypeBuilder] = []; mutable supertypes : Map [TypeInfo, TypeInfo * list [MType]]; mutable member_list : list [IMember] = []; mutable constant_object : IField; mutable underlying_enum_type : MType.Class; //list of instance field initializers public mutable init_list : list [PT.PExpr] = []; [Accessor] mutable tenv : TyVarEnv; internal mutable type_builder : System.Reflection.Emit.TypeBuilder; pt_name : PT.Name; name : string; mutable loc : Location; [Accessor] mutable parts_location : list [Location]; modifiers : Modifiers; accessibility : Accessibility; typarms_count : int; [Accessor (Ast)] mutable pt_tydecl : PT.TopDeclaration; mutable additional_decls : SCG.List [PT.ClassMember] = null; mutable partial_parts : list [PT.TopDeclaration] = []; public AstParts : list [PT.TopDeclaration] { get { System.Diagnostics.Debug.Assert(Manager.IsIntelliSenseMode); pt_tydecl :: partial_parts } } [Accessor (flags = Override)] is_enum : bool; [Accessor (flags = WantSetter)] mutable is_finalized : bool; mutable cannot_finalize : bool; mutable m_has_been_used : bool; /// if it doesn't, we must add implicit empty constructor mutable instance_ctor_occured : bool; /// Marker for [TypeBuilder.Iter]. internal mutable phase : int; mutable is_delegate : bool; public TyManager : TypesManager; /** * Defining type if any and transitive closure of base types of this type. * * Used by [TypeBuilder.Iter] function. */ internal mutable iterate_first : list [TypeBuilder]; internal this (manager : TypesManager, par : TypeBuilder, td : PT.TopDeclaration, ns_node : NamespaceTree.Node) { base (ns_node, manager.Manager, ns_node.GetDisplayName ()); this.TyManager = manager; Manager.Stats.AllTypeBuilders++; this.pt_tydecl = td; this.pt_name = td.ParsedName; when (this.GlobalEnv == null) Util.ice ($ "env is null for $(ns_node.GetDisplayName ())"); this.enclosing_type = par; when (par != null) par.contained_types = this :: par.contained_types; this.name = pt_name.Id; this.loc = td.Location; this.parts_location = [td.Location]; modifiers = td.modifiers; attributes = modifiers.mods; instance_ctor_occured = td is PT.TopDeclaration.Alias; match (td) { | PT.TopDeclaration.VariantOption => instance_ctor_occured = true; enclosing_type.variant_options = this :: enclosing_type.variant_options; attributes |= NemerleAttributes.Sealed; modifiers.custom_attrs = <[ Record ]> :: modifiers.custom_attrs; if (enclosing_type.IsPublic) attributes |= NemerleAttributes.Public else attributes |= NemerleAttributes.Internal; | PT.TopDeclaration.Enum => is_enum = true; | _ => () }; ++Manager.tyinfo_counter; when (pt_tydecl.typarms != null) typarms_count = pt_tydecl.typarms.tyvars.Length; when (par != null) typarms_count += par.TyparmsCount; if (this.pt_tydecl is PT.TopDeclaration.Interface) this.tydecl = TypeDeclaration.Interface (); else this.tydecl = TypeDeclaration.Class (); // may change later (in bind_types) instance_ctor_occured = (attributes %&& (NemerleAttributes.Struct %| NemerleAttributes.Static)) || IsModule || instance_ctor_occured || IsInterface || is_enum; unless (attributes %&& NemerleAttributes.AccessModifiers) if (enclosing_type != null) attributes |= NemerleAttributes.Private; else attributes |= NemerleAttributes.Internal; accessibility = match (attributes %& NemerleAttributes.AccessModifiers) { | NemerleAttributes.Private => Accessibility.Private | NemerleAttributes.Protected => Accessibility.Protected | NemerleAttributes.Internal => Accessibility.Internal | _ => if (attributes %&& (NemerleAttributes.Protected %| NemerleAttributes.Internal)) Accessibility.ProtectedOrInternal else Accessibility.Public } when (enclosing_type != null) accessibility = MType.AccessibilityIntersect (accessibility, enclosing_type.Accessibility); CheckTypeAttributes (); m_has_been_used = IsExternallyAccessible } /** * Return list of type parameters under which we subtype given type. * * For example if [A ['a] :> B [int]], then ["A".SuperType ("B")] * returns [[int]]. * * This information can be also fetched from [GetDirectSuperTypes()] * method but this function is transitive. */ public override SuperType (ti : TypeInfo) : option [list [MType]] { assert (ti != null); assert (supertypes != null); match (supertypes.Find (ti)) { | Some ((_, x)) => Some (x) | None => if (ti.Equals (InternalType.Object_tc)) Some ([]) else if (ti.Equals (this)) Some (Solver.FixedValues (GetMemType ().args)) else None () } } public override IsInterface : bool { get { if (TyManager.run_phase <= 2) pt_tydecl is PT.TopDeclaration.Interface else tydecl is TypeDeclaration.Interface } } public override IsDelegate : bool { get { if (TyManager.run_phase <= 2) is_delegate else InternalType.MulticastDelegate_tc.Equals (BaseType) } } public IsAlias : bool { get { if (TyManager.run_phase <= 2) pt_tydecl is PT.TopDeclaration.Alias else tydecl is TypeDeclaration.Alias } } public IsStruct : bool { get { attributes %&& NemerleAttributes.Struct } } public override IsValueType : bool { get { IsStruct || is_enum } } //TODO: Move it member to parent class public /*override*/ IsVariantOption : bool { get { if (TyManager.run_phase <= 2) pt_tydecl is PT.TopDeclaration.VariantOption else tydecl is TypeDeclaration.VariantOption } } public override GetModifiers () : Modifiers { modifiers } public override GlobalEnv : GlobalEnv { get { pt_name.context } } public ParsedName : PT.Name { get { pt_name } } public ParsedDeclaration : PT.TopDeclaration { get { pt_tydecl } } public ParsedTypeName : PT.PExpr { get { match (typarms) { | [] => <[ $(pt_name : name) ]> | _ => def tparms = typarms.Map (fun (x) { <[ $(pt_name.NewName (x.Name) : name) ]> }); <[ $(pt_name : name).[.. $tparms ] ]> } } } /** Return type we were defined in (null for toplevel types). */ public override DeclaringType : TypeInfo { get { enclosing_type } } /** Return name without any dots. */ public override Name : string { get { name } } public override Accessibility : Accessibility { get { accessibility } } public override IsExternallyAccessible : bool { get { match (accessibility) { | Accessibility.Public | Accessibility.Protected | Accessibility.ProtectedOrInternal => true | _ => false } } } public override UnderlyingType : TypeInfo { get { assert (underlying_enum_type != null); underlying_enum_type.tycon } } public override Location : Location { get { loc } } public SetLocation (loc : Location) : void { this.loc = loc; } public override HasBeenUsed : bool { get { m_has_been_used } set { base.HasBeenUsed = value; m_has_been_used = true; when (enclosing_type != null) Manager.MarkAsUsed (enclosing_type, value) } } public override TyparmsCount : int { get { if (typarms is []) typarms_count else base.TyparmsCount } } public override CanAccess (source : TypeInfo) : bool { IsPublic || (IsInternal && source is TypeBuilder) || (IsProtected && (if (enclosing_type != null) supertypes == null || // during bind_types all supertypes are null Option.IsSome (source.SuperType (enclosing_type)) else false )) || (if (enclosing_type != null) { mutable result = false; for (mutable tc = source; tc != null && !result; tc = tc.DeclaringType) result = tc.Equals (enclosing_type); result } else false ) } [Nemerle.Assertions.Requires (TyManager.run_phase <= 2)] public AddImplementedInterface (t : PT.PExpr) : void { match (pt_tydecl) { | PT.TopDeclaration.Class as td => td.t_extends += [t] | PT.TopDeclaration.Interface as td => td.t_extends += [t] | PT.TopDeclaration.Variant as td => td.t_extends += [t] | _ => Message.Error (pt_tydecl.Location, $"cannot add interface to $(pt_tydecl.GetType().Name.ToLower())" " ($(pt_tydecl.Name)).") } } public DefineNestedType (td : PT.ClassMember.TypeDeclaration, do_fixup : bool) : TypeBuilder { def tyinfo = Manager.NameTree.AddType (this, namespace_nd, td.td); when (do_fixup) tyinfo.FixupDefinedClass (); tyinfo } public DefineNestedType (td : PT.ClassMember.TypeDeclaration) : TypeBuilder { DefineNestedType (td, true) } /** * Adds a definition and returns the new MemberBuilder, if available */ public DefineAndReturn (f : PT.ClassMember) : MemberBuilder { // properties added with quotations have broken names for accessors, fix it match (f) { | Property (get = get, set = set) => match (get) { | Some (d) when d.Name == "get_" => d.name = PT.Splicable.Name (PT.Name ("get_" + f.Name)) | _ => {} } match (set) { | Some (d) when d.Name == "set_" => d.name = PT.Splicable.Name (PT.Name ("set_" + f.Name)) | _ => {} } | _ => {} } when (member_map == null) addToAdditionalDecls (f); add_macros_from_parsedmems (f, MacroPhase.BeforeInheritance); add_macros_from_parsedmems (f, MacroPhase.BeforeTypedMembers); if (member_map == null) null else { try { def mem = bind_and_add_member (f); TyManager.ExpandMacros (); when (TyManager.IsEmitting) { TyManager.EnsureEmitProgress (this); when (IsFinalized) TyManager.MaybeCompile (this, mem); } mem } catch { | _ is Recovery => null } } } public DefineAndReturn (f : PT.ClassMember, do_fixup : bool) : MemberBuilder { match (f) { | PT.ClassMember.TypeDeclaration (Delegate (header) as td) => _ = Delegates.GenerateDelegateClass (this.GlobalEnv, this, td.modifiers, header); null | PT.ClassMember.TypeDeclaration as td => _ = DefineNestedType (td, do_fixup); null | _ => DefineAndReturn (f) } } public DefineWithSource (f : PT.ClassMember, do_fixup = true) : MemberBuilder { TyManager.GenerateFakeSourceCode (f); DefineAndReturn (f, do_fixup) } public Define (f : PT.ClassMember) : void { Define (f, true) } /** * Adds a definition to this type */ public Define (f : PT.ClassMember, do_fixup : bool) : void { _ = DefineAndReturn (f, do_fixup) } /** * Builds this type */ public Compile () : void { unless (cannot_finalize) Nemerle.Imperative.Return (); // avoid repeated calls cannot_finalize = false; when (TyManager.run_phase >= 5) { // Message.Debug ($"comp: $this"); add_constant_variant_ctors (); when (Attributes %&& NemerleAttributes.SpecialName) mark_members_with_special_name (); unless (IsInterface) resolve_method_implements (); check_ctor_constraints (); } when (TyManager.IsEmitting) { // Message.Debug ($"emitimpl: $this -- $(GetDirectMembers ())"); this.CreateEmitDeclarations (); } Manager.Solver.Enqueue (fun () { when (TyManager.run_phase >= 5) { when (TyManager.IsEmitting) { // Message.Debug ($"emitimpl: $this -- $(GetDirectMembers ())"); this.EmitImplementation (); } } Manager.MarkTypeBuilderCompiled (); }) } public FindAttributeWithArgs (looking_for : TypeInfo) : option [PT.PExpr * list [PT.PExpr]] { GetModifiers ().FindAttributeWithArgs (looking_for, this.GlobalEnv) } public FindAttribute (looking_for : TypeInfo) : option [PT.PExpr] { GetModifiers ().FindAttribute (looking_for, this.GlobalEnv) } public override AttributeTargets : System.AttributeTargets { get { // FIXME: System.AttributeTargets.All } } public override HasAttribute (attribute : TypeInfo) : bool { Option.IsSome (FindAttribute (attribute)) } public DisableImplicitConstructor () : void { instance_ctor_occured = true; } public DoBeforeFinalization (action : void -> void) : void { before_finalization.Push (action); } public DoBeforeFinalization2 (action : void -> void) : void { before_finalization2.Push (action); } /** * Marks this with the SpecialName attribute, the attribute will * be propagated to members and contained types at a later stage. */ public MarkWithSpecialName () : void { attributes |= NemerleAttributes.SpecialName } internal MarkAsDelegate () : void { is_delegate = true; MarkWithSpecialName (); } /** * Return list of types that we directly subtype. * * * This includes [extends] and [implements], as well as parent variant * type for variant options. * */ public override GetDirectSuperTypes () : list [MType.Class] { match (parent_type) { | null => t_implements | t => t :: t_implements } } public override GetConstantObject () : IField { constant_object } /** Returns null if there isn't any */ public override BaseType : TypeInfo { get { if (parent_type != null) parent_type.tycon else null } } /** Return type we extend if any. */ public override SuperClass () : option [TypeInfo] { match (parent_type) { | null => None () | _ => Some (parent_type.tycon) } } public override GetTydecl () : TypeDeclaration { tydecl } public override LookupMemberAvailable : bool { get { member_map != null } } public override LookupMemberImpl (name : string) : list [IMember] { match (member_map.Get (name)) { | None => [] | Some (mems) => // FIXME!!!! mems.Filter (fun (mem) { mem.DeclaringType.Equals (this) }) } } /** Searches for the members defined for the current TypeInfo, using the specified binding constraints. Members include properties, methods, fields, events, and so on. The following BindingFlags filter flags can be used to define which members to include in the search: The following BindingFlags modifier flags can be used to change how the search works: BindingFlags.DeclaredOnly to search only the members declared on the TType, not members that were simply inherited. Calling this method with only the Public flag or only the NonPublic flag will return the specified members and does not require any other flags. See Nemerle.Compiler.BindingFlags for more information. */ public override GetMembers (bindingAttr : BindingFlags) : list [IMember] { get_members (bindingAttr, fun (m : IMember) { constrain_member (m, bindingAttr) }) } public override GetMembers () : list [IMember] { get_members (0 :> BindingFlags, fun (_ : IMember) { true }) } public GetParsedMembers (include_manually_defined = false) : list [PT.ClassMember] { match (pt_tydecl) { | PT.TopDeclaration.Class (decls = ds) | PT.TopDeclaration.Interface (methods = ds) | PT.TopDeclaration.Variant (decls = ds) | PT.TopDeclaration.VariantOption (ds) | _ with ds = [] => if (include_manually_defined && additional_decls != null) { mutable result = ds; for (mutable i = additional_decls.Count - 1; i >= 0; i--) result ::= additional_decls[i]; result } else ds }; } public override GetFields (bindingAttr : BindingFlags) : list [IField] { def mems = get_members (bindingAttr, fun (x : IMember) { x.MemberKind == MemberKinds.Field && constrain_member (x, bindingAttr) }); List.Map (mems, fun (x) { x :> IField }) } public GetFields () : list [IField] { def mems = get_members ((0 :> BindingFlags), x => x.MemberKind == MemberKinds.Field); List.Map (mems, fun (x) { x :> IField }) } /** Searches for the methods defined for the current TypeInfo, using the specified binding constraints. */ public GetMethods (bindingAttr : BindingFlags) : list [IMethod] { def mems = get_members (bindingAttr, fun (x : IMember) { if (x.MemberKind == MemberKinds.Method) constrain_member (x, bindingAttr) else false }); List.Map (mems, fun (x) { x :> IMethod }) } public GetMethods () : list [IMethod] { GetMethods (BindingFlags.Static %| BindingFlags.Instance %| BindingFlags.Public %| BindingFlags.NonPublic) } /** Searches for the constructors defined for the current TypeBuilder, using the specified BindingFlags. */ public override GetConstructors (bindingAttr : BindingFlags) : list [IMethod] { def mems = get_members (bindingAttr, fun (x : IMember) { if (x.MemberKind == MemberKinds.Constructor) constrain_member (x, bindingAttr) else false }); List.Map (mems, fun (x) { x :> IMethod }) } public GetConstructors () : list [IMethod] { GetConstructors (BindingFlags.Static %| BindingFlags.Instance %| BindingFlags.Public %| BindingFlags.NonPublic) } /** Searches for the types defined for the current TypeInfo, using the specified BindingFlags. */ public GetNestedTypes (bindingAttr : BindingFlags) : list [TypeInfo] { def mems = get_members (bindingAttr, fun (x : IMember) { x.MemberKind == MemberKinds.NestedType && constrain_member (x, bindingAttr | BindingFlags.Static | BindingFlags.Instance) }); List.Map (mems, fun (x) { x :> TypeInfo }) } public GetNestedTypes () : list [TypeInfo] { GetNestedTypes (BindingFlags.Static %| BindingFlags.Instance %| BindingFlags.Public %| BindingFlags.NonPublic) } public GetProperties (bindingAttr : BindingFlags) : list [IProperty] { def mems = get_members (bindingAttr, fun (x : IMember) { x.MemberKind == MemberKinds.Property && constrain_member (x, bindingAttr) }); List.Map (mems, fun (x) { x :> IProperty }) } public GetProperties () : list [IProperty] { def mems = get_members ((0 :> BindingFlags), fun (x : IMember) { x.MemberKind == MemberKinds.Property }); List.Map (mems, fun (x) { x :> IProperty }) } public GetEvents (bindingAttr : BindingFlags) : list [IEvent] { def mems = get_members (bindingAttr, fun (x : IMember) { x.MemberKind == MemberKinds.Event && constrain_member (x, bindingAttr) }); List.Map (mems, fun (x) { x :> IEvent }) } public GetEvents () : list [IEvent] { def mems = get_members ((0 :> BindingFlags), fun (x : IMember) { x.MemberKind == MemberKinds.Event }); List.Map (mems, fun (x) { x :> IEvent }) } /** Return list of all members defined in this very type. */ public GetDirectMembers () : list [IMember] { member_list } public GetTypeBuilder () : System.Reflection.Emit.TypeBuilder { assert (type_builder != null); type_builder } public GetVariantOptionParent () : TypeBuilder { assert (enclosing_type != null); enclosing_type } public GetVariantOptions () : list [TypeBuilder] { variant_options } /** Return interfaces [this] needs to implement (that is it says it will implement them, but they are not implemented in base class). */ public InterfacesToImplement () : list [TypeInfo] { def base_class = match (parent_type) { | null => InternalType.Object_tc | _ => parent_type.tycon }; def collect (t : MType.Class, acc) { def tc = t.tycon; if (tc.IsInterface) { match (base_class.SuperType (tc)) { | Some =>acc | None => tc :: acc } } else acc }; GetSuperTypes ().FoldLeft ([], collect); } //------------ METHODS FOR TYPING -------------------------------------- /** * Return substitution to apply to types of members of our supertype [ti] * to get types of members in [this]. * * * For example consider: * * class A ['a] { f : 'a; } * class B : A [int] { } * * Now ["B".SubtypingSubst ("A")] would return { 'a := int }, so * it can be applied to type of [A.f] which is ['a], to obtain type * of [B.f] which is [int]. * */ public override SubtypingSubst (tc : TypeInfo) : Subst { if (this.Equals (tc)) Subst () // current type, no substitution else tc.MakeSubst1 (Option.UnSome (SuperType (tc))); } internal ReverseChildren () : void { contained_types = List.Rev (contained_types); variant_options = List.Rev (variant_options); } /** * Construct typing environments for each declaration. * * * The first thing to do is to create typing environment [Tyvar.TEnv] * for each type declaration. Then typing environment is populated * with type variables (transformed into [Tyvar.T] objects). Finally * constraints (type expressions, which are first bound) of each * type variable are stored in [Tyvar.T]. * * Typing environment maps names of type variables to [Tyvar.T] objects. * */ internal make_tyenvs () : void { assert (this.tenv == null); def tenv = TyVarEnv (Manager); match (this.pt_tydecl.typarms) { | null => this.tenv = tenv; this.typarms = []; | ps => // we must merge type parameter constrains from partial parts of this class def ps = List.FoldLeft (partial_parts, ps, fun (part : PT.TopDeclaration, acc : PT.Typarms) { mutable new_constr = acc.constraints; def tparms = match (part) { | PT.TopDeclaration.Class (typarms = t) => t | PT.TopDeclaration.Variant (typarms = t) => t | PT.TopDeclaration.Interface (typarms = t) => t | _ => Util.ice ("non class / variant") } when (! tparms.tyvars.Equals (pt_tydecl.typarms.tyvars)) Message.Error ($ "partial declarations of `$this' must have " "the same type parameter names in the same " "order"); foreach (constr in tparms.constraints) { mutable should_add = true; foreach (con in ps.constraints) when (con.tyvar.GetName().Equals (constr.tyvar.GetName())) should_add = false; when (should_add) new_constr = constr :: new_constr; } if (new_constr : object != acc.constraints) PT.Typarms (acc.tyvars, new_constr) else acc }); (this.tenv, this.typarms) = tenv.AddTyparms (this.GlobalEnv, ps, this, check_parms = false); } when (forced_typarms != null) { Util.cassert (typarms.IsEmpty); typarms = forced_typarms; forced_typarms = null; } // after we updated parsed tenvs of types with partial parts // we should copy them to nested types // we do this using parsetrees, so the fresh StaticVars are used unless (this.pt_tydecl.typarms == null) { def ht = Hashtable (); foreach (tv in this.pt_tydecl.typarms.tyvars) { def nm = tv.GetName (); if (ht.Contains (nm)) Message.Error ($ "duplicate type parameter `$nm'") else ht [nm] = null; } foreach (x in contained_types) { def x = x.ParsedDeclaration; if (x.typarms == null) x.typarms = this.pt_tydecl.typarms; else { def tp1 = this.pt_tydecl.typarms; def tp2 = x.typarms; foreach (tv in tp2.tyvars) when (ht.Contains (tv.GetName ())) { Message.Error (x.Location, $ "type parameter `$(tv.GetName ())' has the same " "name as type parameter from the outer " "type `$(this)'"); Message.Hint ("type parameters are inherited in nested " "types and can be used without declaring " "them explicitly"); } x.typarms = PT.Typarms (tp1.tyvars + tp2.tyvars, tp1.constraints + tp2.constraints) } } } match (pt_tydecl) { | PT.TopDeclaration.VariantOption (members) => unless (Util.is_capitalized (name)) { Message.Error (loc, "variant options' names must start with capital letter") }; foreach (mem in members) mem.Attributes |= NemerleAttributes.Public; | PT.TopDeclaration.Variant => attributes |= NemerleAttributes.Abstract | PT.TopDeclaration.Enum when !this.typarms.IsEmpty => Message.Error ("enums cannot have generic type parameters"); | _ => () }; self_type = MType.Class (this, this.typarms.Map (MType.TyVarRef (_))); foreach (tb in this.contained_types) Util.locate (tb.loc, tb.make_tyenvs ()); } /** * Bind type expressions occurring in type declarations. This * includes [extends] type, [implements] list, and aliased type * in case of type alias declaration. * * * Binding type expression refers to rewriting [Parsetree.Type] * into [Typedtree.TType], which involves resolving names of type * constructors (to [TypeInfo] objects) and type variables (to [Tyvar.T] * objects). * */ internal bind_types () : void { def td = this.pt_tydecl; is_obsolete = HasAttribute (InternalType.Obsolete_tc); this.tenv = this.tenv.CopyWithObsolete (!is_obsolete); this.tydecl = match (td) { | PT.TopDeclaration.Class => TypeDeclaration.Class () | PT.TopDeclaration.Alias (t) => def ttype = this.tenv.MonoBind (this.GlobalEnv, this, t, check_parms = false); TypeDeclaration.Alias (ttype) | PT.TopDeclaration.Interface => TypeDeclaration.Interface () | PT.TopDeclaration.Enum => TypeDeclaration.Enum () | PT.TopDeclaration.Variant => TypeDeclaration.Variant (List.Map (variant_options, fun (x : TypeBuilder) : TypeInfo { x })) | PT.TopDeclaration.VariantOption => TypeDeclaration.VariantOption () | PT.TopDeclaration.Delegate | PT.TopDeclaration.Macro => Util.ice ("this top declaration shouldn't survive to typing") }; def nested_tyvars_subst = if (enclosing_type == null || enclosing_type.typarms is [] || typarms is []) null else { def sub = Subst (); def par_typarms = enclosing_type.typarms; //Message.Debug ($"my typarms=$typarms vs eclosing=$par_typarms"); List.Iter2 (typarms.FirstN (par_typarms.Length), par_typarms, fun (t, pt) { sub.Add (pt, MType.TyVarRef (t)) }); sub } def bind_to_class (t : PT.PExpr) { match (this.tenv.MonoBind (this.GlobalEnv, enclosing_type, t, check_parms = false)) { | MType.Class as tcl => if (nested_tyvars_subst == null) tcl else nested_tyvars_subst.Apply (tcl) :> MType.Class | _ => Message.FatalError2 (t.Location, "derived or implemented type must be a class"); null }; } this.t_implements = []; match (td) { | PT.TopDeclaration.VariantOption => this.parent_type = MType.Class (enclosing_type, typarms.Map (fun (x) { MType.TyVarRef (x) })); | PT.TopDeclaration.Class (t_extends = hd :: tl) | PT.TopDeclaration.Interface (t_extends = hd :: tl) | PT.TopDeclaration.Variant (t_extends = hd :: tl) | PT.TopDeclaration.Enum (t_extends = hd :: tl) => def hd1 = bind_to_class (hd); def itfs = SCG.List(); if (hd1 == null) this.parent_type = null else if (hd1.tycon.IsInterface) { itfs.Add(hd1); this.parent_type = null } else this.parent_type = hd1; foreach (itf in tl) { def bindItf = bind_to_class (itf); when (bindItf != null) itfs.Add(bindItf); } this.t_implements = itfs.ToList(); | _ => this.parent_type = null }; // merge types implemented by partial parts of this class into this TypeBuilder foreach (part in partial_parts) { match (part) { | PT.TopDeclaration.Interface (t_extends = hd :: tail) | PT.TopDeclaration.Class (t_extends = hd :: tail) | PT.TopDeclaration.Variant (t_extends = hd :: tail) => def hd' = bind_to_class (hd); def added_ifaces = if (hd'.tycon.IsInterface) [hd'] else { // if base class exists in both parts, it must be the same match (parent_type) { | null => parent_type = hd' | t => unless (t.tycon.Equals (hd'.tycon)) Message.Error (part.Location, $"Partial declarations of" " `$(FullName)' must not specify different base classes") } []; } // here we merge new interface, removing already declared ones (no errors here) foreach (iface when iface != null in added_ifaces + List.RevMap (tail, bind_to_class)) { mutable should_add = true; foreach (existing in t_implements) when (existing.tycon.Equals (iface.tycon)) should_add = false; when (should_add) t_implements = iface :: t_implements; } | _ => () } } // detect non-interfaces foreach (t in t_implements) unless (t.tycon.IsInterface) Message.Error ($"base class `$t' must be specified as first"); when (is_enum) handle_underlying_enum_type (); when (IsStruct) { // make sure no bogus attributes have been specified def access_mask = NemerleAttributes.AccessModifiers %| NemerleAttributes.Struct | NemerleAttributes.Partial; when ((attributes %& ~access_mask) != NemerleAttributes.None) Message.Error (loc, "structures are only allowed to have access specifiers as attributes"); // mark the structure as sealed attributes |= NemerleAttributes.Sealed; } match (parent_type) { | null => unless (IsInterface || IsAlias) { parent_type = // make the structure inherit from System.ValueType if (IsStruct) InternalType.ValueType; else InternalType.Object; } | tclass => if (IsInterface) { Message.Error (loc, "interfaces are not allowed to inherit from other types"); parent_type = null; } else when (parent_type.tycon.GetTydecl () is TypeDeclaration.Variant && !(tydecl is TypeDeclaration.VariantOption)) { // change current type, so we don't get junk warnings about GetVariantCode tydecl = TypeDeclaration.Class (); Message.Error (loc, "cannot use variant as base type"); } when (IsStruct) { Message.Error (loc, "structures are not allowed to inherit from other types"); parent_type = InternalType.ValueType } when (tclass.tycon.IsSealed) { Message.Error (loc, "cannot extend sealed class"); parent_type = InternalType.Object } when (tclass.tycon.Attributes %&& NemerleAttributes.Static) Message.Error (loc, "cannot derive from module"); } // construct this.iterate_first - enclosing type plus transitive closure of all base types def iterate_first = Hashtable (); foreach (ty : MType.Class in GetDirectSuperTypes ()) match (ty.tycon) { | tb is TypeBuilder => iterate_first.Set (tb, tb) | _ => () } def first = if (enclosing_type != null) [enclosing_type] else []; this.iterate_first = iterate_first.Fold (first, fun (_, ti, acc) { ti :: acc }); foreach (x in contained_types) Util.locate (x.loc, x.bind_types ()); // check variance limitation to interface/delegate type if (IsInterface || IsDelegate) unless (typarms.IsEmpty) foreach (ty in GetDirectSuperTypes ()) unless (MethodBuilder.check_variance_valid (ty, 1)) Message.Error ($"incorrect usage of generic parameters in `$ty' - supertypes must behave covariantly"); else foreach (t when t.IsCovariant || t.IsContravariant in typarms) { Message.Error (".NET runtime allows specifying co/contravariant generic parameters only on interfaces and delegates"); Message.Hint ("vote here to change this miserable state: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94145"); } } internal construct_subtyping_map () : void { def add_srs (t : MType.Class, s : Subinfo) { add_subtyping_of (s, t.tycon, t.args) }; supertypes = List.FoldLeft (GetDirectSuperTypes (), Map (), add_srs); // we should do the additional accessibility checks, which could have // been loosened during bind_types, when supertypes were null foreach (t in GetDirectSuperTypes ()) unless (t.IsAccessibleFrom (this)) Message.Error ($"$t is inaccessible from $this"); foreach (t in typarms) foreach (ct in t.Constraints) unless (ct.IsAccessibleFrom (this)) Message.Error ($"$ct is inaccessible from $this"); when (!this.typarms.IsEmpty && supertypes.Contains (InternalType.Attribute_tc)) Message.Error ($"A generic type cannot derive from `$parent_type' because it is an attribute class"); } add_subtyping_of (subinfo : Subinfo, tc : TypeInfo, args : list [TyVar]) : Subinfo { def add_sr (subinfo : Subinfo, subtyped : TypeInfo, args : list [MType]) { match (subinfo.Find (subtyped)) { | Some ((_, args')) => mutable problem = ""; def check_eq (t1 : MType, t2 : MType) : bool { if (t1.Equals (t2)) true else { problem = $ "types $t1 and $t2 are not compatible"; false } }; unless (List.ForAll2 (args, args', check_eq)) { Message.Error ($ "type `$(subtyped)' is implemented by type " "`$(FullName)' twice under different " "instantiations"); if (tc.Equals (subtyped)) Message.Error ("second one directly") else Message.Error ("second one through `" + tc.FullName + "'"); Message.Error (problem); }; subinfo | None => subinfo.Add (subtyped, (subtyped, args)) } }; def sub = tc.MakeUncheckedSubst (args); def add_srt (t : MType.Class, subinfo : Subinfo) { add_sr (subinfo, t.tycon, List.Map (t.args, fun (t : TyVar) { sub.Apply (t.Fix ()).Fix () }) ) }; def subinfo = List.FoldLeft (tc.GetSuperTypes (), subinfo, add_srt); def subinfo = add_sr (subinfo, tc, Solver.FixedValues (args)); subinfo } public override GetSuperTypes () : list [MType.Class] { if (supertypes == null) [] else supertypes.Fold ([], fun (_, x, acc) { def (tc, args) = x; MType.Class (tc, Solver.MonoTypes (args)) :: acc }) } add_derived_members () : void { def get_members (t : MType.Class) { t.tycon.GetMembers () }; def members = if (IsInterface) List.Concat (List.RevMap (GetDirectSuperTypes (), get_members)) else match (parent_type) { | null => [] | t => get_members (t) } def inherit_it (mem : IMember) { !(mem.MemberKind %&& MemberKinds.Constructor || mem.Attributes %&& NemerleAttributes.Private) }; member_map = Hashtable (); foreach (mem in members) when (inherit_it (mem)) add_member_by_name (mem); member_list = [] } internal ExtendPartialClass (additional : PT.TopDeclaration) : void { if ((Attributes %& additional.Attributes) %&& NemerleAttributes.Partial) { unless (additional.Attributes %&& NemerleAttributes.AccessModifiers) match (enclosing_type) { | null => additional.Attributes |= NemerleAttributes.Internal; | _ => additional.Attributes |= NemerleAttributes.Private; } // we allow abstract and sealed to be specified just on one arbitratry part attributes |= additional.Attributes & (NemerleAttributes.Abstract | NemerleAttributes.Sealed); additional.Attributes |= attributes & (NemerleAttributes.Abstract | NemerleAttributes.Sealed); when (additional.Attributes != attributes) Message.Error (additional.Location, $"joined partial classes `$(FullName)' " "must have compatible modifiers"); } else { Message.Error (additional.Location, "you must specify `partial' modifier on all" " declarations of type `" + FullName + "'"); Message.Error (this.Location, "first defined here"); } match (additional) { | PT.TopDeclaration.Interface (methods = ds) | PT.TopDeclaration.Class (decls = ds) | PT.TopDeclaration.Variant (decls = ds) => partial_parts = additional :: partial_parts; foreach (x : PT.ClassMember in ds) match (x) { | PT.ClassMember.TypeDeclaration => // already added in scan type hierarchy {} | _ => Define (x) } this.parts_location ::= additional.Location; | _ => Message.Error (additional.Location, "`partial' modifier can be used only" " before `class', `struct', `interface' or `variant'") } modifiers.custom_attrs += additional.GetCustomAttributes (); //modifiers.macro_attrs += additional.modifiers.macro_attrs; } internal static constrain_member (m : IMember, flags : BindingFlags) : bool { def is_public = m.Attributes %&& NemerleAttributes.Public; // if flag is Public then always return all public members flags == BindingFlags.Public && is_public || // if flag is NonPublic then always return all nonpublic members flags == BindingFlags.NonPublic && !is_public || // masks (!m.IsStatic || flags %&& BindingFlags.Static) && (m.IsStatic || flags %&& BindingFlags.Instance) && (!is_public || flags %&& BindingFlags.Public) && (is_public || flags %&& BindingFlags.NonPublic) } /** Note that [bindingAttr] is used only to check the case for DeclaredOnly members, so you have to provide filter function to check other flags */ private get_members (bindingAttr : BindingFlags, filter : IMember -> bool) : list [IMember] { def maybe_add (m : IMember, acc) { if (filter(m)) m :: acc else acc }; def add_few (_, mems, acc) { List.FoldLeft (mems, acc, maybe_add) }; if (bindingAttr %&& BindingFlags.DeclaredOnly) List.RevMap (List.RevFilter (member_list, filter), fun (x) { x }) else member_map.Fold ([], add_few) } internal BindType (t : PT.PExpr) : TyVar { BindType (tenv, t) } public MonoBindType (t : PT.PExpr) : MType { MonoBindType (tenv, t) } [Nemerle.Assertions.Requires (t != null)] [Nemerle.Assertions.Ensures (value != null)] internal BindType (other_tenv : TyVarEnv, t : PT.PExpr) : TyVar { other_tenv.Bind (this.GlobalEnv, this, t, allow_tyvars = true, check_parms = true) } public MonoBindType (other_tenv : TyVarEnv, t : PT.PExpr) : MType { other_tenv.MonoBind (this.GlobalEnv, this, t, check_parms = true) } internal BindTyparms (tp : PT.Typarms) : TyVarEnv * list [StaticTyVar] { BindTyparms (tenv, tp) } internal BindTyparms (other_tenv : TyVarEnv, tp : PT.Typarms) : TyVarEnv * list [StaticTyVar] { other_tenv.AddTyparms (this.GlobalEnv, tp, this, check_parms = true) } BindAndAddMember (class_member : PT.ClassMember) : void { try { ignore (bind_and_add_member (class_member)) } catch { | _ is Recovery => () } } internal AddMember (mem : IMember) : void { match (mem) { | mem is MemberBuilder => mem.CheckAttributes (); mem.ProcessMacroAttributes(); | _ => {} } // traverse existing members [mems] searching one which match signature // with the newly added method [meth] // returns new list of members having this name def replace_method (acc, meth : MethodBuilder, mems : list [IMember]) { def par_amount = meth.GetParameters ().Length; match (mems) { // no methods with matching signature found | [] => when (meth.Attributes %&& NemerleAttributes.Override) Message.Error ($"`override' specified on $meth" ", but there is no method with this signature " "in parent to override"); // we simply add this method to the existing list meth :: acc | x :: xs when (x :> IMethod).GetHeader().typarms.Length != meth.GetHeader().typarms.Length => replace_method (x :: acc, meth, xs) // process next member | x :: xs => def m = x :> IMethod; def sub_current = get_method_type_after_subst (m, meth); def sig_matches = (if (meth.Attributes %&& NemerleAttributes.Override) sub_current.Equals (meth.GetMemType ()) else (sub_current :> MType.Fun).from.Equals (meth.GetMemType ().from)) && m.GetParameters ().Length == par_amount; def is_cast_op(m : IMethod) { par_amount == 1 && (m.Name == "op_Implicit" || m.Name == "op_Explicit") && (m is BuiltinMethod || (m.IsStatic && (m.Attributes %&& NemerleAttributes.Public))) } def return_type_overload = sig_matches && m.DeclaringType.Equals (this) && match ((sub_current, meth.GetMemType ())) { | (MType.Fun (t1, r1), MType.Fun (t2, r2)) when t1.Fix ().Equals (t2.Fix ()) && ! r1.Fix ().Equals (r2.Fix ()) => // allow return type overloading for implicit and explicit operators unless (is_cast_op(m) && is_cast_op(meth)) Message.Error(meth.Location, $"attempted return type overload on $meth and $m"); true | _ => false }; // if signature of existing method is the new one if (sig_matches && !return_type_overload) { // check if new method does not hide or conflict with // existing methods in this and base type if (m.DeclaringType.Equals (this)) Message.Error (meth.Location, "redefinition of " + meth.ToString ()) else // new method has 'new' modifier, so it's ok to hide old one if (meth.Attributes %&& NemerleAttributes.New) () else if (meth.Attributes %&& NemerleAttributes.Override) { meth.overridden_method = m; meth.HasBeenUsed = false; if (m.Attributes %&& NemerleAttributes.Virtual) if (m.IsFinal) Message.Error ($"`override' specified on $meth, but $x is `sealed'") else m.HasBeenUsed = !is_obsolete && !meth.IsObsolete; else Message.Error ($"`override' specified on $meth" ", but there is no `virtual' modifier on $x"); when ((x.Attributes %& NemerleAttributes.AccessModifiers) != (meth.Attributes %& NemerleAttributes.AccessModifiers)) Message.Error ($"attempt to change the access modifiers of $meth" " during override of $x"); } else { Message.Warning (114, meth.Location, $"$(meth) hides $(x) inherited from base class. " "To make the current member override that implementation, " "add the `override' keyword. Otherwise add the `new' keyword."); } // return list with the new method inside (and without [x], which is hidden now) List.RevAppend (xs, meth :: acc) } else // signature do not match, just process remaining members replace_method (x :: acc, meth, xs) } }; /* def _meths = GetMethods (); Message.Debug (FullName); foreach (meth in _meths) Message.Debug (meth.ToString ()); */ when (IsValueType && !mem.IsStatic) match (mem) { | fld is IField => match (fld.GetMemType ()) { // enum structs have this special __value field, which is cyclic | MType.Class (tc is TypeBuilder, _) when tc.IsValueType => iterate_first = tc :: iterate_first; | _ => () } | _ => () } def new_mems = match (member_map.Get (mem.Name)) { | Some ([]) => Util.ice () | Some ((x :: _) as old) => if (x.DeclaringType.Equals (this)) match ((mem, x)) { | (m is MethodBuilder, _ is IMethod) => replace_method ([], m, old) | (p1 is IProperty, p2 is IProperty) when p1.IsIndexer && p2.IsIndexer => // overloading is (hopefully) checked at the get/set method level (mem : IMember) :: old | _ => Message.Error (mem.Location, $"$mem redefined in `$(FullName)'"); Message.Error (x.Location, " first definition here as " + x.ToString ()); [mem : IMember] } else // take a look at current member [mem] and the one found in ancestors [x] match ((mem, x)) { | (m is MethodBuilder, _ is IMethod) => replace_method ([], m, old) | (new_prop is PropertyBuilder, old is IProperty) when new_prop.Attributes %&& NemerleAttributes.Override => new_prop.UpdateParentProperty (old); [mem : IMember] | _ when mem.Attributes %&& NemerleAttributes.New => [mem : IMember] | _ => Message.Warning (mem.Location, $"$mem hides $x but neither `override' nor `new' is specified"); [mem : IMember] } | None => when (mem.Attributes %&& NemerleAttributes.Override) Message.Error ($"`override' specified on $mem, " "but there is no such member in parent to override"); [mem : IMember] }; member_map.Set (mem.Name, new_mems); member_list = mem :: member_list; } public CannotFinalize : bool { get { cannot_finalize } internal set { cannot_finalize = value; } } internal FinalizeType () : void { while (!before_finalization.IsEmpty) { def action = before_finalization.Pop (); action () } while (!before_finalization2.IsEmpty) { def action = before_finalization2.Pop (); action () } when (!cannot_finalize && type_builder != null) { // Message.Debug ($"finalize $this"); try { // ok, seemed like this way MS.NET was a little bit more stable // _ = type_builder.CreateType (); // but this also seems to work: system_type = type_builder.CreateType (); } catch { | _ is System.TypeLoadException => // there is a bug in MS.NET // http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=5984e7ff-4a8f-4096-bff9-b459fcd14e89 // it throws this exc for nested value types, but actually assembly is // still being builded properly so we can ignore it () } // // workarond ms.net bug // system_type = type_builder; type_builder = null; } } internal bind_and_add_member (class_member : PT.ClassMember) : MemberBuilder { when (class_member.Env == null) class_member._env = GlobalEnv; Util.locate (class_member.Location, { // if current class is static (it's a module) then sign its members to static when (IsModule) class_member.Attributes |= NemerleAttributes.Static; when (IsInterface) { when (class_member.Attributes %| NemerleAttributes.New != NemerleAttributes.New) Message.Error ("interface members are not allowed" " to have any attributes specified, except 'new'"); class_member.Attributes = class_member.Attributes %| NemerleAttributes.Virtual %| NemerleAttributes.Abstract %| NemerleAttributes.Public; } match (class_member) { | PT.ClassMember.EnumOption | PT.ClassMember.TypeDeclaration => null | (PT.ClassMember.Field) as f => def r = FieldBuilder (this, f); AddMember (r); r : MemberBuilder | (PT.ClassMember.Function) as f => def r = Manager.ComponentsFactory.CreateMethodBuilder (this, f); unless (instance_ctor_occured) instance_ctor_occured = r.MemberKind == MemberKinds.Constructor && !(r.Attributes %&& NemerleAttributes.Static); AddMember (r); r | (PT.ClassMember.Property) as p => def r = PropertyBuilder (this, p); when (r.IsIndexer && r.Name == "Item" && default_indexer == null) { default_indexer = "Item"; modifiers.AddCustomAttribute (<[ System.Reflection.DefaultMemberAttribute ("Item") ]>); } AddMember (r); r | (PT.ClassMember.Event) as e => def r = EventBuilder (this, e); AddMember (r); r } }) } handle_underlying_enum_type () : void { match (parent_type) { | null => underlying_enum_type = InternalType.Int32; | t => when (System.Array.IndexOf.[MType.Class] (InternalType.IntegralTypes, t) == -1) { Message.Error (t.ToString () + " is not valid as an underlying type of enum"); Message.Hint ("Type byte, sbyte, short, ushort, int, uint, long, or ulong expected"); } underlying_enum_type = t; }; parent_type = InternalType.Enum; unless (t_implements.IsEmpty) Message.Error ("enum cannot implement anything"); } /* * This methods calculates an enum's field values. We allow constants, * references to enum fields of this enum that already have been calculated, * arithmetic addition and basic bit-wise operations. */ calculate_enum_value (expr : PT.PExpr, default_value : Literal.Integer, resolved_values : Hashtable [string, Literal.Integer]) : Literal.Integer { def resolve_ref (_, is_post, e) { if (is_post) match (e) { | <[ $(n : name) ]> when resolved_values.Contains (n.Id) => def val = resolved_values [n.Id]; PT.PExpr.Literal (val) | <[ $(n : name) ]> when ConstantFolder.is_known_operator (n.Id) => e | _ => e } else e } def no_refs = Util.locate (expr.Location, { Macros.TraverseExpr (None (), expr, false, resolve_ref) }); match (ConstantFolder.FoldConstants (this.GlobalEnv, no_refs)) { | PT.PExpr.Literal (lit) => match (lit.WithType (underlying_enum_type)) { | Some (l) => l :> Literal.Integer | None => Message.Error (expr.Location, $"supplied value $(lit) cannot be converted to $(underlying_enum_type)" " and isn't valid as enum field initializer"); default_value } | _ => Message.Error (expr.Location, "enum definition expression is too complex"); Message.Hint (expr.Location, " enum definitions are allowed to be expressions taking constants,"); Message.Hint (expr.Location, " references to this enum's fields preceding this field, checked "); Message.Hint (expr.Location, " operations +, <<, >> and -, bit-wise operations |, %, ^ and ~ negation"); default_value } } add_enum_members (decls : list [PT.ClassMember]) : void { def field_type = PT.PExpr.TypedType (GetMemType ()); def resolved_values = Hashtable (32); def add_field (ef : PT.ClassMember, prev_value) { match (ef) { | PT.ClassMember.EnumOption (value) => def current_value = match (value) { | Some (expr) => calculate_enum_value (expr, prev_value, resolved_values) | None => def lit = ConstantFolder.FoldLiterals (true, "+", prev_value, Literal.Integer (1, false, underlying_enum_type)); Literal.Integer (lit.val, lit.is_negative, underlying_enum_type) } assert (current_value.treat_as.Equals (underlying_enum_type)); ef.Attributes |= (NemerleAttributes.Public | NemerleAttributes.Static); def field = <[ decl: ..$(ef.modifiers) $(ef.name) : $field_type; ]>; field.Location = ef.Location; def field = bind_and_add_member (field); (field :> FieldBuilder).ConstValue = current_value; // Message.Debug ($ "add: $(ef.ParsedName.Id) $current_value "); resolved_values.Add (ef.ParsedName.Id, current_value); current_value | _ => Message.Error (ef.Location, "only enum options are allowed in enum"); Message.Hint (ef.Location, "this is the CLR limitation, please vote on " "http://lab.msdn.microsoft.com/productfeedback/" "viewfeedback.aspx?feedbackid=FDBK21375"); prev_value } }; assert (underlying_enum_type != null); def atrs = Modifiers (NemerleAttributes.Public | NemerleAttributes.SpecialName, []); def f = bind_and_add_member (<[ decl: ..$atrs value__ : $(underlying_enum_type : typed); ]>) :> IField; Manager.MarkAsAssigned (f); _ = List.FoldLeft (decls, Literal.Integer (1, true, underlying_enum_type), add_field); } /** * Collect type members (fields and methods, but not types, which * are already collected in [TypeBuilder.contained_types]) and store * them in [TypeInfo.member_map] and [TypeBuilder.member_list]. * * * Members are first transferred from the [Parsetree] into the * [Typedtree] namespace by binding appropriate types. * */ internal add_members () : void { assert (member_list == []); add_derived_members (); // handle enum members separately match (pt_tydecl) { | PT.TopDeclaration.Enum (decls = ds) => add_enum_members (ds); | _ => () }; def decls = GetParsedMembers (); List.Iter (decls, BindAndAddMember); when (additional_decls != null) foreach (m in additional_decls) BindAndAddMember(m); List.Iter (contained_types, AddMember); contained_types = List.Rev (contained_types); member_list = List.Rev (member_list); /// define implicit instance constructor if none exists unless (instance_ctor_occured) { // quasi-quotation use location from top of the Location_stack. // Probably it's location of the class. It will lead to that location will // overlap the locations of other methods. def loc = Location_stack.top ().FromStartAsGenerated (); def ctor = // in abstract classes we have protected implicit ctor, otherwise public // http://www.jaggersoft.com/csharp_standard/17.10.4.htm if (IsAbstract) Util.locate (loc, <[ decl: protected this () { } ]>) else Util.locate (loc, <[ decl: public this () { } ]>); def meth = bind_and_add_member (ctor); meth.SetInstanceUsed (); } // we no longer need it, let GC kill it unless (Manager.IsIntelliSenseMode) { pt_tydecl = null; partial_parts = null; } additional_decls = null; } // in case of variant options, which have only parameterless constructor // and no fields (which could store some data and mane several instances // unique) we will create optimization - all instances of this option will be // replaced by one constant object stored in special static field of this opption's class internal add_constant_object_ctor () : void { def is_pure (tc : TypeInfo) { tc.Equals (InternalType.Object_tc) || (tc is TypeBuilder && match (tc.LookupMember (".ctor")) { | [ctor is MethodBuilder] when ctor.GetParameters ().IsEmpty && tc.GetFields (BindingFlags.Instance %| BindingFlags.Public %| BindingFlags.NonPublic).IsEmpty => //Message.Debug ($ "$tc: ctor.body = $(ctor.Body.GetType()) $(ctor.Body)"); (ctor.Body is <[ { base () } ]> || ctor.Body is <[ {} ]>) && match (tc.SuperClass ()) { | Some (tc) => is_pure (tc) | None => true } | _ => false }) } when (is_pure (this)) { def ttf = GetMemType (); def ctor = match (LookupMember (".ctor")) { | [ctor is MethodBuilder] => ctor | _ => Util.ice (); } ctor.Attributes = NemerleAttributes.Private; Util.locate (loc, { def field = <[ decl: public static _N_constant_object : $(ttf : typed); ]>; constant_object = DefineAndReturn (field) :> IField; // reference to called constructor must be directly in typed version Define (<[ decl: static this () { $(TExpr.Assign (loc, InternalType.Void, TExpr.StaticRef (loc, ttf, ttf, constant_object, []), TExpr.Call (ttf, TExpr.StaticRef (loc, ctor.GetMemType (), ttf, ctor, []), [], false)) : typed); } ]>); // if this constant variant option is serializable // we give the explicit deserialization behaviour to keep the singleton // semantics fo _N_constant_object always def ior = InternalType.IObjectReference.tycon; when (HasAttribute (InternalType.Serializable_tc)) unless (supertypes.Contains (ior)) { t_implements ::= InternalType.IObjectReference; supertypes = supertypes.Add (ior, (ior, [])); def decl = <[ decl: public GetRealObject (_ : System.Runtime.Serialization.StreamingContext) : object { // When deserialiing this object, return a reference to // the Singleton object instead. $(TExpr.StaticRef (loc, ttf, ttf, constant_object, []) : typed); } ]>; decl.Attributes |= NemerleAttributes.SpecialName; Define (decl); } // add the constant object generator function def decl = <[ decl: public static _N_constant_object_generator () : $(ttf : typed) { $(TExpr.StaticRef (loc, ttf, ttf, constant_object, []) : typed) } ]>; decl.Attributes |= NemerleAttributes.SpecialName; Define (decl); }); } } /** * Add special methods to variants and variant options. These methods * are used to accelerate matching over variants, allowing us to use * a single CExpr.Switch statement to identify a variant options instead of * a series of CExpr.If/HasType instructions. * */ internal add_special_variant_methods () : void { match (tydecl) { | TypeDeclaration.Variant => def gvc = <[ decl: public abstract _N_GetVariantCode () : int ; ]>; gvc.Attributes |= NemerleAttributes.SpecialName; Define (gvc) | TypeDeclaration.VariantOption => mutable my_index = 0; _ = List.Find (enclosing_type.GetVariantOptions (), x => (x : object) == this || { ++my_index; false }); def gvc = <[ decl: public override _N_GetVariantCode () : int { $(my_index : int) } ]>; gvc.Attributes |= NemerleAttributes.SpecialName; Define (gvc) | _ => () } } /** * Add constant fields with single instance of parameter-less * variant options. */ internal add_constant_variant_ctors () : void { match (tydecl) { | TypeDeclaration.VariantOption => add_constant_object_ctor () | _ => () } } internal GetTyparms () : list [StaticTyVar] { typarms } internal FixupDefinedClass () : void { // finalization is blocked until call to Compile this.cannot_finalize = true; Util.locate (loc, process_macro_attributes (MacroPhase.BeforeInheritance)); def run_phase = TyManager.run_phase; when (run_phase >= 1) make_tyenvs (); when (run_phase >= 2) Util.locate (loc, bind_types ()); when (run_phase >= 3) construct_subtyping_map (); when (run_phase >= 4) check_bound_types (); when (run_phase >= 5) process_macro_attributes (MacroPhase.BeforeTypedMembers); when (run_phase >= 6) add_members (); when (run_phase >= 7) { process_macro_attributes (MacroPhase.WithTypedMembers); when (TyManager.IsEmitting) TyManager.EnsureEmitProgress (this); } } /** * Propagates the SpecialName mark throughout the member hierarchy */ internal mark_members_with_special_name () : void { foreach (member in member_list) match (member) { | member is MemberBuilder => member.MarkWithSpecialName () | tb is TypeBuilder => tb.MarkWithSpecialName () | _ => Util.ice () } } methods_matches_by_signature (iface_meth : IMethod, meth : IMethod) : bool { if (iface_meth.GetHeader ().typarms.Length == meth.GetHeader ().typarms.Length) { def iftype = get_method_type_after_subst (iface_meth, meth); def methd_type = if (meth.DeclaringType.Equals (this)) meth.GetMemType () else GetMemType ().TypeOfMember (meth).Fix (); methd_type.TrySigRequire (iftype) } else false } get_method_type_after_subst (iface_meth : IMethod, meth : IMethod) : MType { def h1 = iface_meth.GetHeader (); def h2 = meth.GetHeader (); def sub = SubtypingSubst (iface_meth.DeclaringType); unless (h1.typarms.IsEmpty) List.Iter2 (h1.typarms, h2.typarms, fun (stv, target) { sub.Add (stv, MType.TyVarRef (target)) }); sub.MonoApply (iface_meth.GetMemType ()); } /** * Resolves overrides for the required interface methods */ internal resolve_method_implements () : void { check_abstract (); def methods = GetMethods (BindingFlags.DeclaredOnly %| BindingFlags.Public %| BindingFlags.Instance %| BindingFlags.NonPublic); def methods = List.Map (methods, fun (x) { x :> MethodBuilder }); // FIXME: in fact we should only mark some methods as implemented and scream // when signature match is ambiguous // unresolved interface methods, which we must implement def iface_methods = Hashtable (30); def can_explicitly_impl_methods = Hashtable (); def partition_correct_meth (ifmethods, proposed_meth, scream) { def is_correct (iface_meth : IMethod) { // Message.Debug ( $ "try req: $proposed_meth req $iface_meth --- " // "$(proposed_meth.GetMemType ()) req " // "$(GetMemType ().TypeOfMethod (iface_meth))"); if (methods_matches_by_signature (iface_meth, proposed_meth)) if (proposed_meth.Attributes %&& NemerleAttributes.Public && !(proposed_meth.Attributes %&& NemerleAttributes.Static)) true else { when (scream) Message.Error (proposed_meth.Location, "method implementing interface" " member must be public and nonstatic"); false } else false }; List.Partition (ifmethods, is_correct) } def collect_methods (tc, iface_methods) { foreach (m is IMethod in tc.GetMembers (BindingFlags.DeclaredOnly %| BindingFlags.Public %| BindingFlags.Instance)) match (iface_methods.Get (m.Name)) { | Some (lst) => iface_methods.Set (m.Name, m :: lst) | None => iface_methods.Add (m.Name, [m]) }; } foreach (tc : TypeInfo in InterfacesToImplement ()) { // Message.Debug ($ "in $this, $tc .GetMembers == $(tc.GetMembers (BindingFlags.DeclaredOnly %| BindingFlags.Public %| BindingFlags.Instance))"); collect_methods (tc, iface_methods); } foreach (mtype in t_implements) collect_methods (mtype.tycon, can_explicitly_impl_methods); def bind_explicit_implements (meth : MethodBuilder) { def bind_one (impl) { match (impl) { | <[ $ns . $(member : dyn) ]> => def ty = match (Util.QidOfExpr (ns)) { | Some ((idl, name)) => name.context.GetType (idl, this, -1) | _ => match (MonoBindType (ns)) { | Class (tc, _) => tc | m_ty => Message.FatalError ($ "cannot implement method from non-class type $m_ty") } } def is_correct (iface_meth : IMethod) { iface_meth.DeclaringType.Equals (ty) && methods_matches_by_signature (iface_meth, meth) } Manager.MarkAsUsed (meth, !IsObsolete); def partition_and_set (meths, methods_map) { def (correct, notcorrect) = List.Partition (meths, is_correct); match (correct) { | [] => Message.FatalError ($"interface `$(ty.FullName)' does not contain method named" " `$member' with proper signature") | [m] => methods_map.Set (member, notcorrect); m | _ => Message.FatalError ($"interface `$(ty.FullName)' contains more then one method" " named `$member' with proper signature") } } match (iface_methods.Get (member)) { | Some (meths) => partition_and_set (meths, iface_methods); | None => match (can_explicitly_impl_methods.Get (member)) { | Some (meths) => partition_and_set (meths, can_explicitly_impl_methods); | _ => Message.FatalError ($ "no interface implemented by `$FullName' " "contains method named `$member' " "(looking for `$impl')") } } | _ => Message.FatalError ("simple identifier expected in explicit implementation specifier") } }; match (meth.Ast.implemented) { | (_ :: _) as impl => def impl' = try { List.RevMap (impl, bind_one) } catch { _ is Recovery => [] }; // make method virtual, because it implements something // we do it exactly here (not earlier in validity checks), because this // operation is invalid at source code level unless (meth.Attributes %&& NemerleAttributes.Virtual) meth.Attributes |= NemerleAttributes.Sealed %| NemerleAttributes.Virtual %| NemerleAttributes.New; foreach (mem in impl') Manager.MarkAsUsed (mem, !is_obsolete && !meth.IsObsolete); meth.ImplementedMethods = impl'; | _ => meth.ImplementedMethods = []; } }; List.Iter (methods, bind_explicit_implements); def already_bound = Hashtable (); // now we can see which methods defined in current class directly match // to some of the yet unimlemented interfaces methods def bind_implicit_implements (meth : MethodBuilder) { def lookup_iface_members () { match (iface_methods.Get (meth.Name)) { | Some (meths) => match (partition_correct_meth (meths, meth, true)) { | (lst, notcorrect) => iface_methods.Set (meth.Name, notcorrect); def already = if (already_bound.Contains (meth.Name)) { def lst = already_bound [meth.Name] : list [IMethod]; def (additional, _) = partition_correct_meth (lst, meth, false); unless (additional.IsEmpty) Message.Error (meth.Location, $ "ambiguous implements-match for " "interface method(s): $additional, " "please use explicit implementation"); lst } else []; already_bound [meth.Name] = lst + already; unless (lst.IsEmpty) Manager.MarkAsUsed (meth, false); lst } | None => [] } }; match (lookup_iface_members ()) { | [] => () | impl' => def new_impls = impl' + meth.ImplementedMethods; foreach (impl in new_impls) Manager.MarkAsUsed (impl, !is_obsolete && !meth.IsObsolete); meth.ImplementedMethods = new_impls; // Message.Debug ($"setting virtual for $meth $(meth.GetHeader().body) $(meth.Attributes)"); unless (meth.Attributes %&& NemerleAttributes.Virtual) meth.Attributes |= NemerleAttributes.Sealed %| NemerleAttributes.Virtual %| NemerleAttributes.New; // Message.Debug ($"--> $(meth.Attributes)"); } }; List.Iter (methods, bind_implicit_implements); // create the additional overrides for unresolved interface methods // we check if methods derived from base class are actually proper // implementators of some unresolved interface methods mutable resolved_additionals = []; def create_additional_overrides (name : string, mutable meths : list [IMethod]) { unless (meths is []) { // possible implementators from existing methods def possible_impls = LookupMember (name); // choose only methods from within possible implementors foreach (meth is IMethod in possible_impls) { match (partition_correct_meth (meths, meth, false)) { | ([], _) => () | (correct, notcorrect) => meths = notcorrect; // create a wrapper in the current type def meth_header = meth.GetHeader (); def obj = if (meth.IsAbstract) <[ null : this ]> else <[ base ]>; //Message.Debug ("additional " + meth_header.name); def mods = if ((meth.Attributes %&& NemerleAttributes.Virtual) && !(meth.Attributes %&& NemerleAttributes.Sealed)) NemerleAttributes.Override else NemerleAttributes.New; def subst = GetMemType ().ConstructSubstForTypeInfo (meth.DeclaringType); def parse_tr = meth_header.CreateAliasMethod (mods | NemerleAttributes.Public, obj, subst); def wrapper = DefineAndReturn (parse_tr) :> MethodBuilder; wrapper.MarkWithSpecialName (); wrapper.HasBeenUsed = false; // do not trigger obsoletion warning // note in method definition what we are implementing // (this cannot be automatic because we are currently resolving implements wrapper.ImplementedMethods = correct; } } resolved_additionals = (name, meths) :: resolved_additionals; } } iface_methods.Iter (create_additional_overrides); foreach ((name, meths) in resolved_additionals) iface_methods.Set (name, meths); // emit error messages for any unbound interface method def scream_about_unimplemented (_, meths : list [IMethod]) { foreach (meth in meths) // the word ``method'' comes from meth.ToString Message.Error ($ "unimplemented interface $(meth) (in $(this.FullName) type)") } iface_methods.Iter (scream_about_unimplemented); foreach (meth is MethodBuilder in GetMembers ()) when (meth.overridden_method != null) { meth.ImplementedMethods = meth.overridden_method :: meth.ImplementedMethods; meth.overridden_method = null; } } internal process_attributes (self_parm : list [Parsetree.SyntaxElement], target : MacroTargets, stage : MacroPhase, mods : Modifiers, meth : MethodBuilder) : void { mutable macro_attrs = mods.macro_attrs; // we have to do the assignment here, in case macro has added a new // custom attribute def suff = TypesManager.AttributeMacroExpansion.Suffix (target, stage); mods.custom_attrs = mods.custom_attrs.Filter (fun (expr) { match (MacroRegistry.lookup_macro (this.GlobalEnv, expr, suff)) { | None => true | Some => macro_attrs ::= (suff, expr); false } }); mods.macro_attrs = macro_attrs; foreach ((_, expr) in macro_attrs) { def expansion = TypesManager.AttributeMacroExpansion (target, stage, expr, self_parm, this, meth); TyManager.AddMacroExpansion (expansion); }; } add_macros_from_parsedmems (mem : PT.ClassMember, stage : MacroPhase) : void { def syntax_tb = PT.SyntaxElement.TypeBuilder (this); def syntax_mem = PT.SyntaxElement.ClassMember (mem); def parms = [syntax_tb, syntax_mem]; match (mem) { | PT.ClassMember.Field => process_attributes (parms, MacroTargets.Field, stage, mem.modifiers, null) | (PT.ClassMember.Function) as f => process_attributes (parms, MacroTargets.Method, stage, mem.modifiers, null); foreach (p : PT.Fun_parm in f.header.parms) process_attributes ([syntax_tb, syntax_mem, PT.SyntaxElement.Parameter (p)], MacroTargets.Parameter, stage, p.modifiers, null); | PT.ClassMember.EnumOption | PT.ClassMember.TypeDeclaration => () | PT.ClassMember.Property (_, _, _, getr, setr) => process_attributes (parms, MacroTargets.Property, stage, mem.modifiers, null); match (getr) { | Some (m) => add_macros_from_parsedmems (m, stage); | _ => () } match (setr) { | Some (m) => add_macros_from_parsedmems (m, stage); | _ => () } | PT.ClassMember.Event => process_attributes (parms, MacroTargets.Event, stage, mem.modifiers, null) } } internal process_macro_attributes (stage : MacroPhase) : void { process_attributes ([PT.SyntaxElement.TypeBuilder (this)], MacroTargets.Class, stage, modifiers, null); match (stage) { | MacroPhase.BeforeInheritance | MacroPhase.BeforeTypedMembers => foreach (x in GetParsedMembers()) add_macros_from_parsedmems (x, stage); | MacroPhase.WithTypedMembers => () | _ => Util.ice ("cannot run macros processing with none phase") } TyManager.ExpandMacros(); } /* ---------------------------------------------------------------------- */ /* -- VALIDITY CHECKS --------------------------------------------------- */ /* ---------------------------------------------------------------------- */ internal static check_bound_type (t : TyVar) : void { def check_type (t) { | MType.Out (t) | MType.Ref (t) | MType.Array (t, _) => check_tv (t) | MType.Fun (ts, t) => check_tv (ts); check_tv (t) | MType.Void => () | MType.Tuple (ts) => List.Iter (ts, check_tv) | MType.TyVarRef => {} | MType.Class (ti, args) => List.Iter (args, check_tv); _ = ti.MakeSubst (args); | MType.Intersection (lst) => List.Iter (lst, check_type) } and check_tv (t : TyVar) { check_type (t.Fix ()) } check_tv (t) } /** Check if types that are already bound are correctly applied. Check accessibility. */ internal check_bound_types () : void { // check accessibility of type we are aliasing match (tydecl) { | TypeDeclaration.Alias (t) => t.CheckAccessibility (this, accessibility); check_bound_type (t); | _ => () }; // types we are deriving from should be at least as accessible as we foreach (deriv_t : MType.Class in GetDirectSuperTypes ()) { def is_iface = deriv_t.tycon.IsInterface; // access check with exception of interfaces derived / implemented by class // which case is not mentioned by http://www.jaggersoft.com/csharp_standard/10.5.4.htm when (this.IsInterface || !is_iface) deriv_t.CheckAccessibility (this, accessibility); check_bound_type (deriv_t); } foreach (tv in typarms) foreach (t in tv.Constraints) { t.CheckAccessibility (this, accessibility); check_bound_type (t); } } internal check_ctor_constraints () : void { def check_ctors (ty : TypeInfo) { def check_ctor (member : IMember, acc) { if (member.DeclaringType.Equals (ty) && member.MemberKind == MemberKinds.Constructor) { def is_default = (member :> IMethod).GetParameters ().IsEmpty; (acc [0] || is_default, true) } else acc }; List.FoldLeft (ty.GetMembers (), (false, false), check_ctor) }; when (parent_type != null) { def (_, has_ctor) = check_ctors (this); def (par_has_default, par_has_ctor) = check_ctors (parent_type.tycon); when (!has_ctor && !par_has_default && par_has_ctor) Message.Error ("the type `" + FullName + "' has no constructors and the parent type `" + parent_type.tycon.FullName + "' has no default constructor") } } /* * This method emits the warnings about unused global symbols. */ internal check_for_unused_global_symbols () : void { unless (IsDelegate) { def is_variant = !variant_options.IsEmpty; // first, check if this type has ever been referenced when (!(HasBeenUsed || is_variant || IsAlias)) Message.Warning (10003, loc, $"`$this' is not externally visible and has never been referenced"); // then, proceed with the members of this type foreach (member in member_list) { | f is FieldBuilder => when (!f.HasBeenAssigned) if (f.HasBeenUsed) when (!f.IsLiteral && (f.IsPrivate || IsSealed || IsInternal)) Message.Warning (649, member.Location, $"field `$(f.Name)' is never assigned to, and will always have its default value") else Message.Warning (10003, member.Location, $"$member is not externally visible and has never been referenced") | _ is TypeBuilder => () | _ => when (!member.HasBeenUsed) Message.Warning (10003, member.Location, $"$member is not externally visible and has never been referenced") } } } /** * Checks for abstract method in non-abstract class errors. */ check_abstract () : void { // Message.Debug ($"mems $(type_members.ToString(\"\\n\"))"); // check for the abstract method/non-abstract class errors unless (Attributes %&& NemerleAttributes.Abstract) foreach (m is IMethod in GetMembers ()) when (m.Attributes %&& NemerleAttributes.Abstract) { attributes |= NemerleAttributes.Abstract; if (m.DeclaringType.Equals (this)) Message.Error ($"$m is abstract, but its declaring class `$(FullName)' is not"); else Message.Error ($"$m must be overriden, because it is abstract and the current class `$(FullName)' is not"); } } /** * Performs access attributes related checks. Returns an optional * description of the problem. */ internal static CheckAccessAttributes (attrs : NemerleAttributes) : option [string] { def access_attrs_count = (if (attrs %&& NemerleAttributes.Public) 1 else 0) + (if (attrs %&& NemerleAttributes.Internal) 1 else 0) + (if (attrs %&& NemerleAttributes.Protected) 1 else 0) + (if (attrs %&& NemerleAttributes.Private) 1 else 0); def is_protected_internal = attrs %&& NemerleAttributes.Internal && attrs %&& NemerleAttributes.Protected && access_attrs_count == 2; if (access_attrs_count <= 1 || is_protected_internal) None () else Some ("inconsistent access attributes specified") } /** * Performs attributes checks for type definitions. */ internal CheckTypeAttributes () : void { def title () { if (IsInterface) "interface" else (if (IsStruct) "struct" else "type"); } // make sure only a valid subset of NemerleAttributes has been used def check_for_invalid_attr (attr : NemerleAttributes, attr_name : string) { when (attributes %&& attr) Message.FatalError (loc, "invalid attribute `" + attr_name + "' specified for " + title () + ": " + FullName) } check_for_invalid_attr (NemerleAttributes.Virtual, "virtual"); check_for_invalid_attr (NemerleAttributes.Override, "override"); check_for_invalid_attr (NemerleAttributes.Mutable, "mutable"); check_for_invalid_attr (NemerleAttributes.Volatile, "volatile"); // some extra checks for structs and interfaces when (this.IsInterface || this.IsStruct) { check_for_invalid_attr (NemerleAttributes.Abstract, "abstract"); check_for_invalid_attr (NemerleAttributes.Sealed, "sealed"); check_for_invalid_attr (NemerleAttributes.Macro, "macro") } // some extra checks for interfaces when (this.IsInterface) { check_for_invalid_attr (NemerleAttributes.Struct, "struct") } // check the access attributes for consistency match (CheckAccessAttributes (attributes)) { | Some (msg) => Message.FatalError (loc, msg + " for type: " + FullName) | _ => () } def type_is_top_level = enclosing_type == null; // top-level classes can only be public or internal when (type_is_top_level && accessibility != Accessibility.Public && accessibility != Accessibility.Internal) Message.FatalError (loc, "top level " + title () + "s are only allowed to be public or internal: " + FullName); // top-level classes are not allowed to be `new' def type_is_new = attributes %&& NemerleAttributes.New; when (type_is_top_level && type_is_new) Message.FatalError (loc, "only nested " + title () +"s are allowed to `new': " + FullName); // types cannot be abstract and sealed at the same time when (IsAbstract && IsSealed) Message.FatalError (loc, title () + "s are not allowed to be abstract and sealed at the same time: " + FullName) } /// Get direct (derived directly) subtypes of given type. public GetDirectSubTypes() : list[TypeBuilder] { def nameTree = this.GlobalEnv.NameTree; def nsRoot = nameTree.NamespaceTree; def typeBuilders = nsRoot.GetTypeBuilders(); $[ t | t in typeBuilders, t.BaseType : object == this ] } /// Get all subtypes of given type. public GetAllSubTypes() : list[TypeBuilder] { def nameTree = this.GlobalEnv.NameTree; def nsRoot = nameTree.NamespaceTree; def typeBuilders = nsRoot.GetTypeBuilders(); def subTypes = Hashtable(); def getDirectSubTypes(ty) { def subTypes1 = SCG.List(); foreach (t when t.BaseType : object == ty in typeBuilders) unless (subTypes.ContainsKey (t)) { subTypes[t] = 0 : byte; subTypes1.Add(t); } foreach (subType in subTypes1) getDirectSubTypes(subType) } def isImplementInterface(t) { //System.Diagnostics.Trace.Assert(t.Name != "MemberBuilder"); t.t_implements.Exists(x => x.tycon : object == this) } when (IsInterface) foreach (t when t.t_implements != null && isImplementInterface (t) in typeBuilders) unless (subTypes.ContainsKey (t)) { subTypes[t] = 0 : byte; getDirectSubTypes(t); } getDirectSubTypes(this); subTypes.Keys.ToList() } private addToAdditionalDecls (mem : PT.ClassMember) : void { when (additional_decls == null) additional_decls = SCG.List (); additional_decls.Add (mem); } } } // ns