88use pyrefly_graph:: index:: Idx ;
99use pyrefly_python:: ast:: Ast ;
1010use pyrefly_python:: module_path:: ModuleStyle ;
11+ use pyrefly_python:: nesting_context:: NestingContext ;
1112use pyrefly_python:: short_identifier:: ShortIdentifier ;
1213use pyrefly_util:: visit:: VisitMut ;
1314use ruff_python_ast:: Arguments ;
@@ -30,6 +31,7 @@ use ruff_python_ast::ExprYieldFrom;
3031use ruff_python_ast:: Identifier ;
3132use ruff_python_ast:: Operator ;
3233use ruff_python_ast:: StringLiteral ;
34+ use ruff_python_ast:: name:: Name ;
3335use ruff_text_size:: Ranged ;
3436use ruff_text_size:: TextRange ;
3537use starlark_map:: Hashed ;
@@ -549,6 +551,49 @@ impl<'a> BindingsBuilder<'a> {
549551 }
550552 }
551553
554+ fn bind_inline_functional_named_tuple ( & mut self , call : & mut ExprCall ) {
555+ let Some ( kind) = self . as_special_export ( & call. func ) else {
556+ return ;
557+ } ;
558+ let Some ( Expr :: StringLiteral ( name) ) = call. arguments . args . first ( ) else {
559+ return ;
560+ } ;
561+ let class_name = Identifier :: new ( Name :: new ( name. value . to_str ( ) ) , name. range ( ) ) ;
562+ let parent = NestingContext :: toplevel ( ) ;
563+ let class_idx = match kind {
564+ SpecialExport :: CollectionsNamedTuple => {
565+ let Some ( ( _arg_name, members) ) = call. arguments . args . split_first_mut ( ) else {
566+ return ;
567+ } ;
568+ self . synthesize_collections_named_tuple_def (
569+ class_name,
570+ & parent,
571+ & mut call. func ,
572+ members,
573+ & mut call. arguments . keywords ,
574+ false ,
575+ )
576+ }
577+ SpecialExport :: TypingNamedTuple => {
578+ let Some ( ( _arg_name, members) ) = call. arguments . args . split_first_mut ( ) else {
579+ return ;
580+ } ;
581+ self . synthesize_typing_named_tuple_def (
582+ class_name,
583+ & parent,
584+ & mut call. func ,
585+ members,
586+ false ,
587+ )
588+ }
589+ _ => return ,
590+ } ;
591+ self . insert_binding (
592+ Key :: Anon ( call. range ) ,
593+ Binding :: ClassDef ( class_idx, Box :: new ( [ ] ) ) ,
594+ ) ;
595+ }
596+
552597 fn record_yield ( & mut self , mut x : ExprYield ) {
553598 let mut yield_link = self . declare_current_idx ( Key :: YieldLink ( x. range ) ) ;
554599 let idx = self . idx_for_promise ( KeyYield ( x. range ) ) ;
@@ -661,6 +706,14 @@ impl<'a> BindingsBuilder<'a> {
661706 self . finish_bool_op_fork ( ) ;
662707 }
663708 }
709+ Expr :: Call ( call)
710+ if matches ! (
711+ self . as_special_export( & call. func) ,
712+ Some ( SpecialExport :: CollectionsNamedTuple | SpecialExport :: TypingNamedTuple )
713+ ) && matches ! ( call. arguments. args. first( ) , Some ( Expr :: StringLiteral ( _) ) ) =>
714+ {
715+ self . bind_inline_functional_named_tuple ( call) ;
716+ }
664717 Expr :: Call ( ExprCall {
665718 node_index : _,
666719 range : _,
0 commit comments