Skip to content

Commit c245572

Browse files
committed
Auto merge of #143794 - lnicola:ra-backports, r=cuviper
`rust-analyzer` backports Closes rust-lang/rust-analyzer#20182
2 parents b123710 + 07d659c commit c245572

File tree

14 files changed

+562
-110
lines changed

14 files changed

+562
-110
lines changed

src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs

Lines changed: 216 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2815,6 +2815,44 @@ 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(syntax_ptr, fmt, argmap, lit_pieces, format_options)
2829+
} else {
2830+
self.collect_format_args_before_1_89_0_impl(
2831+
syntax_ptr,
2832+
fmt,
2833+
argmap,
2834+
lit_pieces,
2835+
format_options,
2836+
)
2837+
};
2838+
2839+
self.source_map
2840+
.template_map
2841+
.get_or_insert_with(Default::default)
2842+
.format_args_to_captures
2843+
.insert(idx, (hygiene, mappings));
2844+
idx
2845+
}
2846+
2847+
/// `format_args!` expansion implementation for rustc versions < `1.89.0`
2848+
fn collect_format_args_before_1_89_0_impl(
2849+
&mut self,
2850+
syntax_ptr: AstPtr<ast::Expr>,
2851+
fmt: FormatArgs,
2852+
argmap: FxIndexSet<(usize, ArgumentType)>,
2853+
lit_pieces: ExprId,
2854+
format_options: ExprId,
2855+
) -> ExprId {
28182856
let arguments = &*fmt.arguments.arguments;
28192857

28202858
let args = if arguments.is_empty() {
@@ -2902,19 +2940,189 @@ impl ExprCollector<'_> {
29022940
});
29032941
}
29042942

2905-
let idx = self.alloc_expr(
2943+
self.alloc_expr(
29062944
Expr::Call {
29072945
callee: new_v1_formatted,
29082946
args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
29092947
},
29102948
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
2949+
)
2950+
}
2951+
2952+
/// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
2953+
/// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
2954+
fn collect_format_args_impl(
2955+
&mut self,
2956+
syntax_ptr: AstPtr<ast::Expr>,
2957+
fmt: FormatArgs,
2958+
argmap: FxIndexSet<(usize, ArgumentType)>,
2959+
lit_pieces: ExprId,
2960+
format_options: ExprId,
2961+
) -> ExprId {
2962+
let arguments = &*fmt.arguments.arguments;
2963+
2964+
let (let_stmts, args) = if arguments.is_empty() {
2965+
(
2966+
// Generate:
2967+
// []
2968+
vec![],
2969+
self.alloc_expr_desugared(Expr::Array(Array::ElementList {
2970+
elements: Box::default(),
2971+
})),
2972+
)
2973+
} else if argmap.len() == 1 && arguments.len() == 1 {
2974+
// Only one argument, so we don't need to make the `args` tuple.
2975+
//
2976+
// Generate:
2977+
// super let args = [<core::fmt::Arguments>::new_display(&arg)];
2978+
let args = argmap
2979+
.iter()
2980+
.map(|&(arg_index, ty)| {
2981+
let ref_arg = self.alloc_expr_desugared(Expr::Ref {
2982+
expr: arguments[arg_index].expr,
2983+
rawness: Rawness::Ref,
2984+
mutability: Mutability::Shared,
2985+
});
2986+
self.make_argument(ref_arg, ty)
2987+
})
2988+
.collect();
2989+
let args =
2990+
self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
2991+
let args_name = Name::new_symbol_root(sym::args);
2992+
let args_binding = self.alloc_binding(
2993+
args_name.clone(),
2994+
BindingAnnotation::Unannotated,
2995+
HygieneId::ROOT,
2996+
);
2997+
let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
2998+
self.add_definition_to_binding(args_binding, args_pat);
2999+
// TODO: We don't have `super let` yet.
3000+
let let_stmt = Statement::Let {
3001+
pat: args_pat,
3002+
type_ref: None,
3003+
initializer: Some(args),
3004+
else_branch: None,
3005+
};
3006+
(vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into())))
3007+
} else {
3008+
// Generate:
3009+
// super let args = (&arg0, &arg1, &...);
3010+
let args_name = Name::new_symbol_root(sym::args);
3011+
let args_binding = self.alloc_binding(
3012+
args_name.clone(),
3013+
BindingAnnotation::Unannotated,
3014+
HygieneId::ROOT,
3015+
);
3016+
let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
3017+
self.add_definition_to_binding(args_binding, args_pat);
3018+
let elements = arguments
3019+
.iter()
3020+
.map(|arg| {
3021+
self.alloc_expr_desugared(Expr::Ref {
3022+
expr: arg.expr,
3023+
rawness: Rawness::Ref,
3024+
mutability: Mutability::Shared,
3025+
})
3026+
})
3027+
.collect();
3028+
let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
3029+
// TODO: We don't have `super let` yet
3030+
let let_stmt1 = Statement::Let {
3031+
pat: args_pat,
3032+
type_ref: None,
3033+
initializer: Some(args_tuple),
3034+
else_branch: None,
3035+
};
3036+
3037+
// Generate:
3038+
// super let args = [
3039+
// <core::fmt::Argument>::new_display(args.0),
3040+
// <core::fmt::Argument>::new_lower_hex(args.1),
3041+
// <core::fmt::Argument>::new_debug(args.0),
3042+
// …
3043+
// ];
3044+
let args = argmap
3045+
.iter()
3046+
.map(|&(arg_index, ty)| {
3047+
let args_ident_expr =
3048+
self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
3049+
let arg = self.alloc_expr_desugared(Expr::Field {
3050+
expr: args_ident_expr,
3051+
name: Name::new_tuple_field(arg_index),
3052+
});
3053+
self.make_argument(arg, ty)
3054+
})
3055+
.collect();
3056+
let array =
3057+
self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
3058+
let args_binding = self.alloc_binding(
3059+
args_name.clone(),
3060+
BindingAnnotation::Unannotated,
3061+
HygieneId::ROOT,
3062+
);
3063+
let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
3064+
self.add_definition_to_binding(args_binding, args_pat);
3065+
let let_stmt2 = Statement::Let {
3066+
pat: args_pat,
3067+
type_ref: None,
3068+
initializer: Some(array),
3069+
else_branch: None,
3070+
};
3071+
(vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
3072+
};
3073+
3074+
// Generate:
3075+
// &args
3076+
let args = self.alloc_expr_desugared(Expr::Ref {
3077+
expr: args,
3078+
rawness: Rawness::Ref,
3079+
mutability: Mutability::Shared,
3080+
});
3081+
3082+
let call_block = {
3083+
// Generate:
3084+
// unsafe {
3085+
// <core::fmt::Arguments>::new_v1_formatted(
3086+
// lit_pieces,
3087+
// args,
3088+
// format_options,
3089+
// )
3090+
// }
3091+
3092+
let new_v1_formatted = LangItem::FormatArguments.ty_rel_path(
3093+
self.db,
3094+
self.module.krate(),
3095+
Name::new_symbol_root(sym::new_v1_formatted),
3096+
);
3097+
let new_v1_formatted =
3098+
self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
3099+
let args = [lit_pieces, args, format_options];
3100+
let call = self
3101+
.alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
3102+
3103+
Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
3104+
};
3105+
3106+
if !let_stmts.is_empty() {
3107+
// Generate:
3108+
// {
3109+
// super let …
3110+
// super let …
3111+
// <core::fmt::Arguments>::new_…(…)
3112+
// }
3113+
let call = self.alloc_expr_desugared(call_block);
3114+
self.alloc_expr(
3115+
Expr::Block {
3116+
id: None,
3117+
statements: let_stmts.into(),
3118+
tail: Some(call),
3119+
label: None,
3120+
},
3121+
syntax_ptr,
3122+
)
3123+
} else {
3124+
self.alloc_expr(call_block, syntax_ptr)
3125+
}
29183126
}
29193127

29203128
/// Generate a hir expression for a format_args placeholder specification.

0 commit comments

Comments
 (0)