@@ -2815,6 +2815,51 @@ impl ExprCollector<'_> {
28152815 mutability : Mutability :: Shared ,
28162816 } )
28172817 } ;
2818+
2819+ // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
2820+ // but `format_unsafe_arg` does not
2821+ let fmt_args =
2822+ || crate :: lang_item:: lang_item ( self . db , self . module . krate ( ) , LangItem :: FormatArguments ) ;
2823+ let fmt_unsafe_arg =
2824+ || crate :: lang_item:: lang_item ( self . db , self . module . krate ( ) , LangItem :: FormatUnsafeArg ) ;
2825+ let use_format_args_since_1_89_0 = fmt_args ( ) . is_some ( ) && fmt_unsafe_arg ( ) . is_none ( ) ;
2826+
2827+ let idx = if use_format_args_since_1_89_0 {
2828+ self . collect_format_args_impl (
2829+ syntax_ptr,
2830+ fmt,
2831+ hygiene,
2832+ argmap,
2833+ lit_pieces,
2834+ format_options,
2835+ )
2836+ } else {
2837+ self . collect_format_args_before_1_89_0_impl (
2838+ syntax_ptr,
2839+ fmt,
2840+ argmap,
2841+ lit_pieces,
2842+ format_options,
2843+ )
2844+ } ;
2845+
2846+ self . source_map
2847+ . template_map
2848+ . get_or_insert_with ( Default :: default)
2849+ . format_args_to_captures
2850+ . insert ( idx, ( hygiene, mappings) ) ;
2851+ idx
2852+ }
2853+
2854+ /// `format_args!` expansion implementation for rustc versions < `1.89.0`
2855+ fn collect_format_args_before_1_89_0_impl (
2856+ & mut self ,
2857+ syntax_ptr : AstPtr < ast:: Expr > ,
2858+ fmt : FormatArgs ,
2859+ argmap : FxIndexSet < ( usize , ArgumentType ) > ,
2860+ lit_pieces : ExprId ,
2861+ format_options : ExprId ,
2862+ ) -> ExprId {
28182863 let arguments = & * fmt. arguments . arguments ;
28192864
28202865 let args = if arguments. is_empty ( ) {
@@ -2902,19 +2947,181 @@ impl ExprCollector<'_> {
29022947 } ) ;
29032948 }
29042949
2905- let idx = self . alloc_expr (
2950+ self . alloc_expr (
29062951 Expr :: Call {
29072952 callee : new_v1_formatted,
29082953 args : Box :: new ( [ lit_pieces, args, format_options, unsafe_arg_new] ) ,
29092954 } ,
29102955 syntax_ptr,
2911- ) ;
2912- self . source_map
2913- . template_map
2914- . get_or_insert_with ( Default :: default)
2915- . format_args_to_captures
2916- . insert ( idx, ( hygiene, mappings) ) ;
2917- idx
2956+ )
2957+ }
2958+
2959+ /// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
2960+ /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
2961+ fn collect_format_args_impl (
2962+ & mut self ,
2963+ syntax_ptr : AstPtr < ast:: Expr > ,
2964+ fmt : FormatArgs ,
2965+ hygiene : HygieneId ,
2966+ argmap : FxIndexSet < ( usize , ArgumentType ) > ,
2967+ lit_pieces : ExprId ,
2968+ format_options : ExprId ,
2969+ ) -> ExprId {
2970+ let arguments = & * fmt. arguments . arguments ;
2971+
2972+ let ( let_stmts, args) = if arguments. is_empty ( ) {
2973+ (
2974+ // Generate:
2975+ // []
2976+ vec ! [ ] ,
2977+ self . alloc_expr_desugared ( Expr :: Array ( Array :: ElementList {
2978+ elements : Box :: default ( ) ,
2979+ } ) ) ,
2980+ )
2981+ } else if argmap. len ( ) == 1 && arguments. len ( ) == 1 {
2982+ // Only one argument, so we don't need to make the `args` tuple.
2983+ //
2984+ // Generate:
2985+ // super let args = [<core::fmt::Arguments>::new_display(&arg)];
2986+ let args = argmap
2987+ . iter ( )
2988+ . map ( |& ( arg_index, ty) | {
2989+ let ref_arg = self . alloc_expr_desugared ( Expr :: Ref {
2990+ expr : arguments[ arg_index] . expr ,
2991+ rawness : Rawness :: Ref ,
2992+ mutability : Mutability :: Shared ,
2993+ } ) ;
2994+ self . make_argument ( ref_arg, ty)
2995+ } )
2996+ . collect ( ) ;
2997+ let args =
2998+ self . alloc_expr_desugared ( Expr :: Array ( Array :: ElementList { elements : args } ) ) ;
2999+ let args_name = Name :: new_symbol_root ( sym:: args) ;
3000+ let args_binding =
3001+ self . alloc_binding ( args_name. clone ( ) , BindingAnnotation :: Unannotated , hygiene) ;
3002+ let args_pat = self . alloc_pat_desugared ( Pat :: Bind { id : args_binding, subpat : None } ) ;
3003+ self . add_definition_to_binding ( args_binding, args_pat) ;
3004+ // TODO: We don't have `super let` yet.
3005+ let let_stmt = Statement :: Let {
3006+ pat : args_pat,
3007+ type_ref : None ,
3008+ initializer : Some ( args) ,
3009+ else_branch : None ,
3010+ } ;
3011+ ( vec ! [ let_stmt] , self . alloc_expr_desugared ( Expr :: Path ( Path :: from ( args_name) ) ) )
3012+ } else {
3013+ // Generate:
3014+ // super let args = (&arg0, &arg1, &...);
3015+ let args_name = Name :: new_symbol_root ( sym:: args) ;
3016+ let args_binding =
3017+ self . alloc_binding ( args_name. clone ( ) , BindingAnnotation :: Unannotated , hygiene) ;
3018+ let args_pat = self . alloc_pat_desugared ( Pat :: Bind { id : args_binding, subpat : None } ) ;
3019+ self . add_definition_to_binding ( args_binding, args_pat) ;
3020+ let elements = arguments
3021+ . iter ( )
3022+ . map ( |arg| {
3023+ self . alloc_expr_desugared ( Expr :: Ref {
3024+ expr : arg. expr ,
3025+ rawness : Rawness :: Ref ,
3026+ mutability : Mutability :: Shared ,
3027+ } )
3028+ } )
3029+ . collect ( ) ;
3030+ let args_tuple = self . alloc_expr_desugared ( Expr :: Tuple { exprs : elements } ) ;
3031+ // TODO: We don't have `super let` yet
3032+ let let_stmt1 = Statement :: Let {
3033+ pat : args_pat,
3034+ type_ref : None ,
3035+ initializer : Some ( args_tuple) ,
3036+ else_branch : None ,
3037+ } ;
3038+
3039+ // Generate:
3040+ // super let args = [
3041+ // <core::fmt::Argument>::new_display(args.0),
3042+ // <core::fmt::Argument>::new_lower_hex(args.1),
3043+ // <core::fmt::Argument>::new_debug(args.0),
3044+ // …
3045+ // ];
3046+ let args = argmap
3047+ . iter ( )
3048+ . map ( |& ( arg_index, ty) | {
3049+ let args_ident_expr =
3050+ self . alloc_expr_desugared ( Expr :: Path ( args_name. clone ( ) . into ( ) ) ) ;
3051+ let arg = self . alloc_expr_desugared ( Expr :: Field {
3052+ expr : args_ident_expr,
3053+ name : Name :: new_tuple_field ( arg_index) ,
3054+ } ) ;
3055+ self . make_argument ( arg, ty)
3056+ } )
3057+ . collect ( ) ;
3058+ let array =
3059+ self . alloc_expr_desugared ( Expr :: Array ( Array :: ElementList { elements : args } ) ) ;
3060+ let args_binding =
3061+ self . alloc_binding ( args_name. clone ( ) , BindingAnnotation :: Unannotated , hygiene) ;
3062+ let args_pat = self . alloc_pat_desugared ( Pat :: Bind { id : args_binding, subpat : None } ) ;
3063+ self . add_definition_to_binding ( args_binding, args_pat) ;
3064+ let let_stmt2 = Statement :: Let {
3065+ pat : args_pat,
3066+ type_ref : None ,
3067+ initializer : Some ( array) ,
3068+ else_branch : None ,
3069+ } ;
3070+ ( vec ! [ let_stmt1, let_stmt2] , self . alloc_expr_desugared ( Expr :: Path ( args_name. into ( ) ) ) )
3071+ } ;
3072+
3073+ // Generate:
3074+ // &args
3075+ let args = self . alloc_expr_desugared ( Expr :: Ref {
3076+ expr : args,
3077+ rawness : Rawness :: Ref ,
3078+ mutability : Mutability :: Shared ,
3079+ } ) ;
3080+
3081+ let call_block = {
3082+ // Generate:
3083+ // unsafe {
3084+ // <core::fmt::Arguments>::new_v1_formatted(
3085+ // lit_pieces,
3086+ // args,
3087+ // format_options,
3088+ // )
3089+ // }
3090+
3091+ let new_v1_formatted = LangItem :: FormatArguments . ty_rel_path (
3092+ self . db ,
3093+ self . module . krate ( ) ,
3094+ Name :: new_symbol_root ( sym:: new_v1_formatted) ,
3095+ ) ;
3096+ let new_v1_formatted =
3097+ self . alloc_expr_desugared ( new_v1_formatted. map_or ( Expr :: Missing , Expr :: Path ) ) ;
3098+ let args = [ lit_pieces, args, format_options] ;
3099+ let call = self
3100+ . alloc_expr_desugared ( Expr :: Call { callee : new_v1_formatted, args : args. into ( ) } ) ;
3101+
3102+ Expr :: Unsafe { id : None , statements : Box :: default ( ) , tail : Some ( call) }
3103+ } ;
3104+
3105+ if !let_stmts. is_empty ( ) {
3106+ // Generate:
3107+ // {
3108+ // super let …
3109+ // super let …
3110+ // <core::fmt::Arguments>::new_…(…)
3111+ // }
3112+ let call = self . alloc_expr_desugared ( call_block) ;
3113+ self . alloc_expr (
3114+ Expr :: Block {
3115+ id : None ,
3116+ statements : let_stmts. into ( ) ,
3117+ tail : Some ( call) ,
3118+ label : None ,
3119+ } ,
3120+ syntax_ptr,
3121+ )
3122+ } else {
3123+ self . alloc_expr ( call_block, syntax_ptr)
3124+ }
29183125 }
29193126
29203127 /// Generate a hir expression for a format_args placeholder specification.
0 commit comments