@@ -11,7 +11,7 @@ use base_db::FxIndexSet;
11
11
use cfg:: CfgOptions ;
12
12
use either:: Either ;
13
13
use hir_expand:: {
14
- HirFileId , InFile , Intern , MacroDefId ,
14
+ HirFileId , InFile , MacroDefId ,
15
15
mod_path:: tool_path,
16
16
name:: { AsName , Name } ,
17
17
span_map:: SpanMapRef ,
@@ -2148,7 +2148,7 @@ impl ExprCollector<'_> {
2148
2148
) -> ExprId {
2149
2149
let block_id = self . expander . ast_id_map ( ) . ast_id_for_block ( & block) . map ( |file_local_id| {
2150
2150
let ast_id = self . expander . in_file ( file_local_id) ;
2151
- BlockLoc { ast_id, module : self . module } . intern ( self . db )
2151
+ self . db . intern_block ( BlockLoc { ast_id, module : self . module } )
2152
2152
} ) ;
2153
2153
2154
2154
let ( module, def_map) =
@@ -2815,6 +2815,51 @@ impl ExprCollector<'_> {
2815
2815
mutability : Mutability :: Shared ,
2816
2816
} )
2817
2817
} ;
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 {
2818
2863
let arguments = & * fmt. arguments . arguments ;
2819
2864
2820
2865
let args = if arguments. is_empty ( ) {
@@ -2902,19 +2947,181 @@ impl ExprCollector<'_> {
2902
2947
} ) ;
2903
2948
}
2904
2949
2905
- let idx = self . alloc_expr (
2950
+ self . alloc_expr (
2906
2951
Expr :: Call {
2907
2952
callee : new_v1_formatted,
2908
2953
args : Box :: new ( [ lit_pieces, args, format_options, unsafe_arg_new] ) ,
2909
2954
} ,
2910
2955
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
+ }
2918
3125
}
2919
3126
2920
3127
/// Generate a hir expression for a format_args placeholder specification.
0 commit comments