fn gen_members_extends(
    instance_name: &str,
    pos: Pos,
    pu_members: Vec<Tast::PuMember>,
) -> Tast::Method_ {
    let assign = |target, expr| {
        let binop = Tast::Expr_::Binop(Box::new((ast_defs::Bop::Eq(None), target, expr)));
        let expr = Tast::Expr(pos.clone(), binop);
        let stmt_ = Tast::Stmt_::Expr(Box::new(expr));
        Tast::Stmt(pos.clone(), stmt_)
    };
    let assign_lvar = |target, expr| assign(lvar(pos.clone(), target), expr);
    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_::Collection(Box::new((
        ast_defs::Id(pos.clone(), "keyset".to_string()),
        None,
        members,
    )));
    let mems = Tast::Expr(pos.clone(), mems_);
    let body = {
        let ast = vec![
            /* $result = keyset[ ... names of local instances ... ] */
            assign_lvar("$result".to_string(), mems),
            /* $class = new ReflectionClass(parent::class) */
            assign_lvar(
                "$class".to_string(),
                new_(
                    pos.clone(),
                    "ReflectionClass".to_string(),
                    vec![class_const(
                        pos.clone(),
                        "parent".to_string(),
                        "class".to_string(),
                    )],
                ),
            ),
            Tast::Stmt(
                pos.clone(),
                /* try { */
                Tast::Stmt_::Try(Box::new((
                    vec![
                        /* $method = $class->getMethod('pu$E$Members'); */
                        assign_lvar(
                            "$method".to_string(),
                            call(
                                pos.clone(),
                                obj_get(pos.clone(), "$class".to_string(), "getMethod".to_string()),
                                vec![str_(pos.clone(), m_members.clone())],
                            ),
                        ),
                        /* $parent_members = $method->invoke(null); */
                        assign_lvar(
                            "$parent_members".to_string(),
                            call(
                                pos.clone(),
                                obj_get(pos.clone(), "$method".to_string(), "invoke".to_string()),
                                vec![Tast::Expr(pos.clone(), Tast::Expr_::Null)],
                            ),
                        ),
                        /* foreach ($parent_members as $p) { $result[] = $p; } */
                        Tast::Stmt(
                            pos.clone(),
                            Tast::Stmt_::Foreach(Box::new((
                                lvar(pos.clone(), "$parent_members".to_string()),
                                Tast::AsExpr::AsV(lvar(pos.clone(), "$p".to_string())),
                                vec![assign(
                                    Tast::Expr(
                                        pos.clone(),
                                        Tast::Expr_::ArrayGet(Box::new((
                                            lvar(pos.clone(), "$result".to_string()),
                                            None,
                                        ))),
                                    ),
                                    lvar(pos.clone(), "$p".to_string()),
                                )],
                            ))),
                        ),
                    ],
                    /* } 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![],
                ))),
            ),
            /* return $result; */
            return_(pos.clone(), lvar(pos.clone(), "$result".to_string())),
        ];
        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![],
        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.
   We thus systematically perform a call to Members() in the parent class to
   check if there are instances of the PU defined in the superclass.
   As the Members method might not exist in the 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.

  <<__Memoize, __Override>>
  public static function pu$E$Members() : keyset<string> {
    $result = keyset[ .. strings based on local PU instances ...];
    $class = new ReflectionClass(parent::class);
    try {
      // 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.
We thus systematically perform a call to Members() in the parent class to
check if there are instances of the PU defined in the superclass.
As the Members method might not exist in the 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.

<<__Memoize, __Override>>
public static function pu$E$Members() : keyset {
$result = keyset[ ..
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 . We thus systematically perform a call to Members () in the parent class to check if there are instances of the PU defined in the superclass . As the Members method might not exist in the 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 . <<__Memoize __Override >> public static function pu$E$Members () : keyset { $result = keyset [ ..
fn gen_members_extends(
    instance_name: &str,
    pos: Pos,
    pu_members: Vec<Tast::PuMember>,
) -> Tast::Method_ {
    let assign = |target, expr| {
        let binop = Tast::Expr_::Binop(Box::new((ast_defs::Bop::Eq(None), target, expr)));
        let expr = Tast::Expr(pos.clone(), binop);
        let stmt_ = Tast::Stmt_::Expr(Box::new(expr));
        Tast::Stmt(pos.clone(), stmt_)
    };
    let assign_lvar = |target, expr| assign(lvar(pos.clone(), target), expr);
    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_::Collection(Box::new((
        ast_defs::Id(pos.clone(), "keyset".to_string()),
        None,
        members,
    )));
    let mems = Tast::Expr(pos.clone(), mems_);
    let body = {
        let ast = vec![
            /* $result = keyset[ ... names of local instances ... ] */
            assign_lvar("$result".to_string(), mems),
            /* $class = new ReflectionClass(parent::class) */
            assign_lvar(
                "$class".to_string(),
                new_(
                    pos.clone(),
                    "ReflectionClass".to_string(),
                    vec![class_const(
                        pos.clone(),
                        "parent".to_string(),
                        "class".to_string(),
                    )],
                ),
            ),
            Tast::Stmt(
                pos.clone(),
                /* try { */
                Tast::Stmt_::Try(Box::new((
                    vec![
                        /* $method = $class->getMethod('pu$E$Members'); */
                        assign_lvar(
                            "$method".to_string(),
                            call(
                                pos.clone(),
                                obj_get(pos.clone(), "$class".to_string(), "getMethod".to_string()),
                                vec![str_(pos.clone(), m_members.clone())],
                            ),
                        ),
                        /* $parent_members = $method->invoke(null); */
                        assign_lvar(
                            "$parent_members".to_string(),
                            call(
                                pos.clone(),
                                obj_get(pos.clone(), "$method".to_string(), "invoke".to_string()),
                                vec![Tast::Expr(pos.clone(), Tast::Expr_::Null)],
                            ),
                        ),
                        /* foreach ($parent_members as $p) { $result[] = $p; } */
                        Tast::Stmt(
                            pos.clone(),
                            Tast::Stmt_::Foreach(Box::new((
                                lvar(pos.clone(), "$parent_members".to_string()),
                                Tast::AsExpr::AsV(lvar(pos.clone(), "$p".to_string())),
                                vec![assign(
                                    Tast::Expr(
                                        pos.clone(),
                                        Tast::Expr_::ArrayGet(Box::new((
                                            lvar(pos.clone(), "$result".to_string()),
                                            None,
                                        ))),
                                    ),
                                    lvar(pos.clone(), "$p".to_string()),
                                )],
                            ))),
                        ),
                    ],
                    /* } 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![],
                ))),
            ),
            /* return $result; */
            return_(pos.clone(), lvar(pos.clone(), "$result".to_string())),
        ];
        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![],
        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_extends ( instance_name : & str , pos : Pos , pu_members : Vec < Tast :: PuMember > , ) -> Tast :: Method_ { let assign = | target , expr | { let binop = Tast :: Expr_ :: Binop ( Box :: new ( ( ast_defs :: Bop :: Eq ( None ) , target , expr ) ) ) ; let expr = Tast :: Expr ( pos . clone ( ) , binop ) ; let stmt_ = Tast :: Stmt_ :: Expr ( Box :: new ( expr ) ) ; Tast :: Stmt ( pos . clone ( ) , stmt_ ) } ; let assign_lvar = | target , expr | assign ( lvar ( pos . clone ( ) , target ) , expr ) ; 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_ :: Collection ( Box :: new ( ( ast_defs :: Id ( pos . clone ( ) , " " . to_string ( ) ) , None , members , ) ) ) ; let mems = Tast :: Expr ( pos . clone ( ) , mems_ ) ; let body = { let ast = vec ! [ /* $result = keyset[ ... names of local instances ... ] */ assign_lvar ( " " to_string ( ) mems ) /* $class = new ReflectionClass(parent::class) */ assign_lvar ( " " to_string ( ) new_ ( pos clone ( ) " " to_string ( ) vec [ class_const ( pos clone ( ) " " to_string ( ) " " to_string ( ) ) ] ) ) Tast Stmt ( pos clone ( ) /* try { */ Tast Stmt_ Try ( Box new ( ( vec [ /* $method = $class->getMethod('pu$E$Members'); */ assign_lvar ( " " to_string ( ) call ( pos clone ( ) obj_get ( pos clone ( ) " " to_string ( ) " " to_string ( ) ) vec [ str_ ( pos clone ( ) m_members clone ( ) ) ] ) ) /* $parent_members = $method->invoke(null); */ assign_lvar ( " " to_string ( ) call ( pos clone ( ) obj_get ( pos clone ( ) " " to_string ( ) " " to_string ( ) ) vec [ Tast Expr ( pos clone ( ) Tast Expr_ Null ) ] ) ) /* foreach ($parent_members as $p) { $result[] = $p; } */ Tast Stmt ( pos clone ( ) Tast Stmt_ Foreach ( Box new ( ( lvar ( pos clone ( ) " " to_string ( ) ) Tast AsExpr AsV ( lvar ( pos clone ( ) " " to_string ( ) ) ) vec [ assign ( Tast Expr ( pos clone ( ) Tast Expr_ ArrayGet ( Box new ( ( lvar ( pos clone ( ) " " to_string ( ) ) None ) ) ) ) lvar ( pos clone ( ) " " to_string ( ) ) ) ] ) ) ) ) ] /* } catch (ReflectionException $_) { } */ vec [ Tast Catch ( ast_defs Id ( pos clone ( ) " " to_string ( ) ) aast Lid ( pos clone ( ) local_id make_unscoped ( " " to_string ( ) ) ) vec [ ] ) ] vec [ ] ) ) ) ) /* return $result; */ return_ ( pos clone ( ) lvar ( pos clone ( ) " " to_string ( ) ) ) ] ; 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 ! [ ] , 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.
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 .
instance_name
&str
pos
Pos
pu_members
Vec<Tast::PuMember>