fn gen_members_search(
    instance_name: &str,
    pos: Pos,
    extends: bool,
    uses: &[&str],
    pu_members: Vec<Tast::PuMember>,
) -> Tast::Method_ {
    let m_members = pu_name_mangle(instance_name, "Members");
    let members = pu_members
        .into_iter()
        .map(|member: Tast::PuMember| {
            let atom = member.atom.1;
            Tast::Afield::AFvalue(str_(pos.clone(), atom))
        })
        .collect();
    let mems_ = Tast::Expr_::mk_collection(
        ast_defs::Id(pos.clone(), "keyset".to_string()),
        None,
        members,
    );
    let mems = Tast::Expr(pos.clone(), mems_);
    let uses_list: Vec<Tast::Afield> = uses
        .iter()
        .map(|x| Tast::Afield::AFvalue(str_(pos.clone(), string_utils::strip_ns(x).to_string())))
        .collect();
    let update_members_from = |expr: Tast::Expr| {
        vec![Tast::Stmt(
            pos.clone(),
            /* try { */
            Tast::Stmt_::mk_try(
                vec![
                    /* $class = new ReflectionClass(parent::class / $traits_class) */
                    assign_lvar(
                        pos.clone(),
                        "$class",
                        new_(pos.clone(), "ReflectionClass", vec![expr]),
                    ),
                    /* $method = $class->getMethod('pu$E$Members'); */
                    assign_lvar(
                        pos.clone(),
                        "$method",
                        call(
                            pos.clone(),
                            obj_get(pos.clone(), "$class", "getMethod"),
                            vec![str_(pos.clone(), m_members.clone())],
                        ),
                    ),
                    /* $parent_members = $method->invoke(null); */
                    assign_lvar(
                        pos.clone(),
                        "$parent_members",
                        call(
                            pos.clone(),
                            obj_get(pos.clone(), "$method", "invoke"),
                            vec![Tast::Expr(pos.clone(), Tast::Expr_::Null)],
                        ),
                    ),
                    /* foreach ($parent_members as $p) { $result[] = $p; } */
                    Tast::Stmt(
                        pos.clone(),
                        Tast::Stmt_::mk_foreach(
                            lvar(pos.clone(), "$parent_members"),
                            Tast::AsExpr::AsV(lvar(pos.clone(), "$p")),
                            vec![assign(
                                pos.clone(),
                                Tast::Expr(
                                    pos.clone(),
                                    Tast::Expr_::mk_array_get(lvar(pos.clone(), "$result"), None),
                                ),
                                lvar(pos.clone(), "$p"),
                            )],
                        ),
                    ),
                ],
                /* } catch (ReflectionException $_) { } */
                vec![Tast::Catch(
                    ast_defs::Id(pos.clone(), "ReflectionException".to_string()),
                    aast::Lid(pos.clone(), local_id::make_unscoped("$_".to_string())),
                    vec![],
                )],
                vec![],
            ),
        )]
    };
    let members_traits = if uses.is_empty() {
        vec![]
    } else {
        vec![
            /* $traits_classes = vec[ ... used traits ...] */
            assign_lvar(
                pos.clone(),
                "$traits_classes",
                Tast::Expr(
                    pos.clone(),
                    Tast::Expr_::mk_collection(
                        ast_defs::Id(pos.clone(), "vec".to_string()),
                        None,
                        uses_list,
                    ),
                ),
            ),
            /* foreach ($traits_classes as $traits_class) */
            Tast::Stmt(
                pos.clone(),
                Tast::Stmt_::mk_foreach(
                    lvar(pos.clone(), "$traits_classes"),
                    Tast::AsExpr::AsV(lvar(pos.clone(), "$traits_class")),
                    update_members_from(lvar(pos.clone(), "$traits_class")),
                ),
            ),
        ]
    };
    let members_parent = if !extends {
        vec![]
    } else {
        update_members_from(class_const(pos.clone(), "parent", "class"))
    };
    let body = {
        let mut ast = vec![
            /* $result = keyset[ ... names of local instances ... ] */
            assign_lvar(pos.clone(), "$result", mems),
        ];
        ast.extend(members_traits);
        ast.extend(members_parent);
        ast.extend(vec![
            /* return $result; */
            return_(pos.clone(), lvar(pos.clone(), "$result")),
        ]);
        Tast::FuncBody {
            ast,
            annotation: (),
        }
    };
    Tast::Method_ {
        span: pos.clone(),
        annotation: (),
        final_: false,
        abstract_: false,
        static_: true,
        visibility: aast_defs::Visibility::Public,
        name: ast_defs::Id(pos.clone(), m_members),
        tparams: vec![],
        where_constraints: vec![],
        variadic: Tast::FunVariadicity::FVnonVariadic,
        params: vec![],
        cap: create_mixed_type_hint(pos.clone()),
        unsafe_cap: create_mixed_type_hint(pos.clone()),
        body,
        fun_kind: ast_defs::FunKind::FSync,
        user_attributes: vec![memoize(pos.clone()), override_(pos.clone())],
        ret: create_key_set_string_type_hint(pos),
        external: false,
        doc_comment: None,
    }
}
/* As for accessors, we do not have a reliable way to detect, whenever a
   PU is defined in a subclass, if the PU is inherited from the superclass,
   or if instances are defined in traits being used.  We thus systematically
   perform a call to Members() in the used traits and in the parent class to
   check if there are instances of the PU defined in the trait/superclass.
   As the Members method might not exist in the trait/superclass, we encapsulate
   the call using reflection and catch the eventual exception.
   Reflection can be slow, but Memoization ensures that the class hierarchy
   is explored only once.

   The general shape is:

  <<__Memoize, __Override>>
  public static function pu$E$Members() : keyset<string> {
    $result = keyset[ .. strings based on local PU instances ...];
    // exploring used traits
    $traits = vec[ ... used traits ...];
    foreach ($traits as $traits_class) {
      try {
        $class = new ReflectionClass($traits_class);
        // might throw if the method is not in the parent class
        $method = $class->getMethod('pu$E$Members');
        // method is here, call it
        $parent_members = $method->invoke(null);
        foreach ($parent_members as $p) {
          $result[] = $p;
        }
      } catch (ReflectionException $_) {
      }
    }
    // exploring the parent
    try {
      $class = new ReflectionClass(parent::class);
      // might throw if the method is not in the parent class
      $method = $class->getMethod('pu$E$Members');
      // method is here, call it
      $parent_members = $method->invoke(null);
      foreach ($parent_members as $p) {
        $result[] = $p;
      }
    } catch (ReflectionException $_) {
      // not the right method: just use local info
    }
   return $result;
  }
*/
As for accessors, we do not have a reliable way to detect, whenever a
PU is defined in a subclass, if the PU is inherited from the superclass,
or if instances are defined in traits being used.  We thus systematically
perform a call to Members() in the used traits and in the parent class to
check if there are instances of the PU defined in the trait/superclass.
As the Members method might not exist in the trait/superclass, we encapsulate
the call using reflection and catch the eventual exception.
Reflection can be slow, but Memoization ensures that the class hierarchy
is explored only once.

The general shape is.

<<__Memoize, __Override>>
public static function pu$E$Members() : keyset {
$result = keyset[ .. strings based on local PU instances ...];
exploring used traits
$traits = vec[ ...
As for accessors we do not have a reliable way to detect whenever a PU is defined in a subclass if the PU is inherited from the superclass or if instances are defined in traits being used . We thus systematically perform a call to Members () in the used traits and in the parent class to check if there are instances of the PU defined in the trait / superclass . As the Members method might not exist in the trait / superclass we encapsulate the call using reflection and catch the eventual exception . Reflection can be slow but Memoization ensures that the class hierarchy is explored only once . The general shape is . <<__Memoize __Override >> public static function pu$E$Members () : keyset { $result = keyset [ .. strings based on local PU instances ... ] ; exploring used traits $traits = vec [ ...
fn gen_members_search(
    instance_name: &str,
    pos: Pos,
    extends: bool,
    uses: &[&str],
    pu_members: Vec<Tast::PuMember>,
) -> Tast::Method_ {
    let m_members = pu_name_mangle(instance_name, "Members");
    let members = pu_members
        .into_iter()
        .map(|member: Tast::PuMember| {
            let atom = member.atom.1;
            Tast::Afield::AFvalue(str_(pos.clone(), atom))
        })
        .collect();
    let mems_ = Tast::Expr_::mk_collection(
        ast_defs::Id(pos.clone(), "keyset".to_string()),
        None,
        members,
    );
    let mems = Tast::Expr(pos.clone(), mems_);
    let uses_list: Vec<Tast::Afield> = uses
        .iter()
        .map(|x| Tast::Afield::AFvalue(str_(pos.clone(), string_utils::strip_ns(x).to_string())))
        .collect();
    let update_members_from = |expr: Tast::Expr| {
        vec![Tast::Stmt(
            pos.clone(),
            /* try { */
            Tast::Stmt_::mk_try(
                vec![
                    /* $class = new ReflectionClass(parent::class / $traits_class) */
                    assign_lvar(
                        pos.clone(),
                        "$class",
                        new_(pos.clone(), "ReflectionClass", vec![expr]),
                    ),
                    /* $method = $class->getMethod('pu$E$Members'); */
                    assign_lvar(
                        pos.clone(),
                        "$method",
                        call(
                            pos.clone(),
                            obj_get(pos.clone(), "$class", "getMethod"),
                            vec![str_(pos.clone(), m_members.clone())],
                        ),
                    ),
                    /* $parent_members = $method->invoke(null); */
                    assign_lvar(
                        pos.clone(),
                        "$parent_members",
                        call(
                            pos.clone(),
                            obj_get(pos.clone(), "$method", "invoke"),
                            vec![Tast::Expr(pos.clone(), Tast::Expr_::Null)],
                        ),
                    ),
                    /* foreach ($parent_members as $p) { $result[] = $p; } */
                    Tast::Stmt(
                        pos.clone(),
                        Tast::Stmt_::mk_foreach(
                            lvar(pos.clone(), "$parent_members"),
                            Tast::AsExpr::AsV(lvar(pos.clone(), "$p")),
                            vec![assign(
                                pos.clone(),
                                Tast::Expr(
                                    pos.clone(),
                                    Tast::Expr_::mk_array_get(lvar(pos.clone(), "$result"), None),
                                ),
                                lvar(pos.clone(), "$p"),
                            )],
                        ),
                    ),
                ],
                /* } catch (ReflectionException $_) { } */
                vec![Tast::Catch(
                    ast_defs::Id(pos.clone(), "ReflectionException".to_string()),
                    aast::Lid(pos.clone(), local_id::make_unscoped("$_".to_string())),
                    vec![],
                )],
                vec![],
            ),
        )]
    };
    let members_traits = if uses.is_empty() {
        vec![]
    } else {
        vec![
            /* $traits_classes = vec[ ... used traits ...] */
            assign_lvar(
                pos.clone(),
                "$traits_classes",
                Tast::Expr(
                    pos.clone(),
                    Tast::Expr_::mk_collection(
                        ast_defs::Id(pos.clone(), "vec".to_string()),
                        None,
                        uses_list,
                    ),
                ),
            ),
            /* foreach ($traits_classes as $traits_class) */
            Tast::Stmt(
                pos.clone(),
                Tast::Stmt_::mk_foreach(
                    lvar(pos.clone(), "$traits_classes"),
                    Tast::AsExpr::AsV(lvar(pos.clone(), "$traits_class")),
                    update_members_from(lvar(pos.clone(), "$traits_class")),
                ),
            ),
        ]
    };
    let members_parent = if !extends {
        vec![]
    } else {
        update_members_from(class_const(pos.clone(), "parent", "class"))
    };
    let body = {
        let mut ast = vec![
            /* $result = keyset[ ... names of local instances ... ] */
            assign_lvar(pos.clone(), "$result", mems),
        ];
        ast.extend(members_traits);
        ast.extend(members_parent);
        ast.extend(vec![
            /* return $result; */
            return_(pos.clone(), lvar(pos.clone(), "$result")),
        ]);
        Tast::FuncBody {
            ast,
            annotation: (),
        }
    };
    Tast::Method_ {
        span: pos.clone(),
        annotation: (),
        final_: false,
        abstract_: false,
        static_: true,
        visibility: aast_defs::Visibility::Public,
        name: ast_defs::Id(pos.clone(), m_members),
        tparams: vec![],
        where_constraints: vec![],
        variadic: Tast::FunVariadicity::FVnonVariadic,
        params: vec![],
        cap: create_mixed_type_hint(pos.clone()),
        unsafe_cap: create_mixed_type_hint(pos.clone()),
        body,
        fun_kind: ast_defs::FunKind::FSync,
        user_attributes: vec![memoize(pos.clone()), override_(pos.clone())],
        ret: create_key_set_string_type_hint(pos),
        external: false,
        doc_comment: None,
    }
}
fn gen_members_search ( instance_name : & str , pos : Pos , extends : bool , uses : & [ & str ] , pu_members : Vec < Tast :: PuMember > , ) -> Tast :: Method_ { let m_members = pu_name_mangle ( instance_name , " " ) ; let members = pu_members . into_iter ( ) . map ( | member : Tast :: PuMember | { let atom = member . atom . 1 ; Tast :: Afield :: AFvalue ( str_ ( pos . clone ( ) , atom ) ) } ) . collect ( ) ; let mems_ = Tast :: Expr_ :: mk_collection ( ast_defs :: Id ( pos . clone ( ) , " " . to_string ( ) ) , None , members , ) ; let mems = Tast :: Expr ( pos . clone ( ) , mems_ ) ; let uses_list : Vec < Tast :: Afield > = uses . iter ( ) . map ( | x | Tast :: Afield :: AFvalue ( str_ ( pos . clone ( ) , string_utils :: strip_ns ( x ) . to_string ( ) ) ) ) . collect ( ) ; let update_members_from = | expr : Tast :: Expr | { vec ! [ Tast Stmt ( pos clone ( ) /* try { */ Tast Stmt_ mk_try ( vec [ /* $class = new ReflectionClass(parent::class / $traits_class) */ assign_lvar ( pos clone ( ) " " new_ ( pos clone ( ) " " vec [ expr ] ) ) /* $method = $class->getMethod('pu$E$Members'); */ assign_lvar ( pos clone ( ) " " call ( pos clone ( ) obj_get ( pos clone ( ) " " " " ) vec [ str_ ( pos clone ( ) m_members clone ( ) ) ] ) ) /* $parent_members = $method->invoke(null); */ assign_lvar ( pos clone ( ) " " call ( pos clone ( ) obj_get ( pos clone ( ) " " " " ) vec [ Tast Expr ( pos clone ( ) Tast Expr_ Null ) ] ) ) /* foreach ($parent_members as $p) { $result[] = $p; } */ Tast Stmt ( pos clone ( ) Tast Stmt_ mk_foreach ( lvar ( pos clone ( ) " " ) Tast AsExpr AsV ( lvar ( pos clone ( ) " " ) ) vec [ assign ( pos clone ( ) Tast Expr ( pos clone ( ) Tast Expr_ mk_array_get ( lvar ( pos clone ( ) " " ) None ) ) lvar ( pos clone ( ) " " ) ) ] ) ) ] /* } catch (ReflectionException $_) { } */ vec [ Tast Catch ( ast_defs Id ( pos clone ( ) " " to_string ( ) ) aast Lid ( pos clone ( ) local_id make_unscoped ( " " to_string ( ) ) ) vec [ ] ) ] vec [ ] ) ) ] } ; let members_traits = if uses . is_empty ( ) { vec ! [ ] } else { vec ! [ /* $traits_classes = vec[ ... used traits ...] */ assign_lvar ( pos clone ( ) " " Tast Expr ( pos clone ( ) Tast Expr_ mk_collection ( ast_defs Id ( pos clone ( ) " " to_string ( ) ) None uses_list ) ) ) /* foreach ($traits_classes as $traits_class) */ Tast Stmt ( pos clone ( ) Tast Stmt_ mk_foreach ( lvar ( pos clone ( ) " " ) Tast AsExpr AsV ( lvar ( pos clone ( ) " " ) ) update_members_from ( lvar ( pos clone ( ) " " ) ) ) ) ] } ; let members_parent = if ! extends { vec ! [ ] } else { update_members_from ( class_const ( pos . clone ( ) , " " , " " ) ) } ; let body = { let mut ast = vec ! [ /* $result = keyset[ ... names of local instances ... ] */ assign_lvar ( pos clone ( ) " " mems ) ] ; ast . extend ( members_traits ) ; ast . extend ( members_parent ) ; ast . extend ( vec ! [ /* return $result; */ return_ ( pos clone ( ) lvar ( pos clone ( ) " " ) ) ] ) ; Tast :: FuncBody { ast , annotation : ( ) , } } ; Tast :: Method_ { span : pos . clone ( ) , annotation : ( ) , final_ : false , abstract_ : false , static_ : true , visibility : aast_defs :: Visibility :: Public , name : ast_defs :: Id ( pos . clone ( ) , m_members ) , tparams : vec ! [ ] , where_constraints : vec ! [ ] , variadic : Tast :: FunVariadicity :: FVnonVariadic , params : vec ! [ ] , cap : create_mixed_type_hint ( pos . clone ( ) ) , unsafe_cap : create_mixed_type_hint ( pos . clone ( ) ) , body , fun_kind : ast_defs :: FunKind :: FSync , user_attributes : vec ! [ memoize ( pos clone ( ) ) override_ ( pos clone ( ) ) ] , ret : create_key_set_string_type_hint ( pos ) , external : false , doc_comment : None , } }
As for accessors, we do not have a reliable way to detect, whenever a
PU is defined in a subclass, if the PU is inherited from the superclass,
or if instances are defined in traits being used.
As for accessors we do not have a reliable way to detect whenever a PU is defined in a subclass if the PU is inherited from the superclass or if instances are defined in traits being used .
instance_name
&str
pos
Pos
extends
bool
uses
&[&str]
pu_members
Vec<Tast::PuMember>