Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #19531 from Veykril/push-kxyrpznnllkx
fix: Fix `format_args` lowering for >=1.87
Lukas Wirth 2025-04-06
parent bec5459 · parent e7ce86d · commit 7e00f91
-rw-r--r--crates/base-db/src/lib.rs13
-rw-r--r--crates/hir-def/src/expr_store/lower.rs137
-rw-r--r--crates/hir-ty/src/infer.rs12
-rw-r--r--crates/hir/src/diagnostics.rs13
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/intern/src/symbol/symbols.rs5
-rw-r--r--crates/project-model/src/workspace.rs1
7 files changed, 129 insertions, 54 deletions
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs
index 83857cf2dd..9fbeace76c 100644
--- a/crates/base-db/src/lib.rs
+++ b/crates/base-db/src/lib.rs
@@ -303,6 +303,19 @@ pub struct CrateWorkspaceData {
pub toolchain: Option<Version>,
}
+impl CrateWorkspaceData {
+ pub fn is_atleast_187(&self) -> bool {
+ const VERSION_187: Version = Version {
+ major: 1,
+ minor: 87,
+ patch: 0,
+ pre: Prerelease::EMPTY,
+ build: BuildMetadata::EMPTY,
+ };
+ self.toolchain.as_ref().map_or(false, |v| *v >= VERSION_187)
+ }
+}
+
fn toolchain_channel(db: &dyn RootQueryDb, krate: Crate) -> Option<ReleaseChannel> {
krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre))
}
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 2d6e8f037f..1791a1c317 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -2321,54 +2321,99 @@ impl ExprCollector<'_> {
zero_pad,
debug_hex,
} = &placeholder.format_options;
- let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
- let align = {
- let align = LangItem::FormatAlignment.ty_rel_path(
- self.db,
- self.krate,
- match alignment {
- Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left.clone()),
- Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right.clone()),
- Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center.clone()),
- None => Name::new_symbol_root(sym::Unknown.clone()),
- },
- );
- match align {
- Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
- None => self.missing_expr(),
- }
- };
- // This needs to match `Flag` in library/core/src/fmt/rt.rs.
- let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
- | (((sign == Some(FormatSign::Minus)) as u32) << 1)
- | ((alternate as u32) << 2)
- | ((zero_pad as u32) << 3)
- | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4)
- | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5);
- let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
- flags as u128,
- Some(BuiltinUint::U32),
- )));
- let precision = self.make_count(precision, argmap);
- let width = self.make_count(width, argmap);
+ let precision_expr = self.make_count(precision, argmap);
+ let width_expr = self.make_count(width, argmap);
- let format_placeholder_new = {
- let format_placeholder_new = LangItem::FormatPlaceholder.ty_rel_path(
- self.db,
- self.krate,
- Name::new_symbol_root(sym::new.clone()),
- );
- match format_placeholder_new {
- Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
- None => self.missing_expr(),
- }
- };
-
- self.alloc_expr_desugared(Expr::Call {
- callee: format_placeholder_new,
- args: Box::new([position, fill, align, flags, precision, width]),
- })
+ if self.krate.workspace_data(self.db).is_atleast_187() {
+ // These need to match the constants in library/core/src/fmt/rt.rs.
+ let align = match alignment {
+ Some(FormatAlignment::Left) => 0,
+ Some(FormatAlignment::Right) => 1,
+ Some(FormatAlignment::Center) => 2,
+ None => 3,
+ };
+ // This needs to match `Flag` in library/core/src/fmt/rt.rs.
+ let flags = fill.unwrap_or(' ') as u32
+ | ((sign == Some(FormatSign::Plus)) as u32) << 21
+ | ((sign == Some(FormatSign::Minus)) as u32) << 22
+ | (alternate as u32) << 23
+ | (zero_pad as u32) << 24
+ | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
+ | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
+ | (width.is_some() as u32) << 27
+ | (precision.is_some() as u32) << 28
+ | align << 29
+ | 1 << 31; // Highest bit always set.
+ let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ flags as u128,
+ Some(BuiltinUint::U32),
+ )));
+
+ let position = RecordLitField {
+ name: Name::new_symbol_root(sym::position.clone()),
+ expr: position,
+ };
+ let flags =
+ RecordLitField { name: Name::new_symbol_root(sym::flags.clone()), expr: flags };
+ let precision = RecordLitField {
+ name: Name::new_symbol_root(sym::precision.clone()),
+ expr: precision_expr,
+ };
+ let width = RecordLitField {
+ name: Name::new_symbol_root(sym::width.clone()),
+ expr: width_expr,
+ };
+ self.alloc_expr_desugared(Expr::RecordLit {
+ path: LangItem::FormatPlaceholder.path(self.db, self.krate).map(Box::new),
+ fields: Box::new([position, flags, precision, width]),
+ spread: None,
+ })
+ } else {
+ let format_placeholder_new = {
+ let format_placeholder_new = LangItem::FormatPlaceholder.ty_rel_path(
+ self.db,
+ self.krate,
+ Name::new_symbol_root(sym::new.clone()),
+ );
+ match format_placeholder_new {
+ Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
+ None => self.missing_expr(),
+ }
+ };
+ // This needs to match `Flag` in library/core/src/fmt/rt.rs.
+ let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
+ | (((sign == Some(FormatSign::Minus)) as u32) << 1)
+ | ((alternate as u32) << 2)
+ | ((zero_pad as u32) << 3)
+ | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4)
+ | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5);
+ let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ flags as u128,
+ Some(BuiltinUint::U32),
+ )));
+ let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
+ let align = {
+ let align = LangItem::FormatAlignment.ty_rel_path(
+ self.db,
+ self.krate,
+ match alignment {
+ Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left.clone()),
+ Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right.clone()),
+ Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center.clone()),
+ None => Name::new_symbol_root(sym::Unknown.clone()),
+ },
+ );
+ match align {
+ Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
+ None => self.missing_expr(),
+ }
+ };
+ self.alloc_expr_desugared(Expr::Call {
+ callee: format_placeholder_new,
+ args: Box::new([position, fill, align, flags, precision_expr, width_expr]),
+ })
+ }
}
/// Generate a hir expression for a format_args Count.
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 0bd605c18b..0448ecd1ec 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -1534,10 +1534,6 @@ impl<'a> InferenceContext<'a> {
None => return (self.err_ty(), None),
}
};
- let Some(mod_path) = path.mod_path() else {
- never!("resolver should always resolve lang item paths");
- return (self.err_ty(), None);
- };
return match resolution {
TypeNs::AdtId(AdtId::StructId(strukt)) => {
let substs = path_ctx.substs_from_path(strukt.into(), true);
@@ -1567,6 +1563,10 @@ impl<'a> InferenceContext<'a> {
let Some(remaining_idx) = unresolved else {
drop(ctx);
+ let Some(mod_path) = path.mod_path() else {
+ never!("resolver should always resolve lang item paths");
+ return (self.err_ty(), None);
+ };
return self.resolve_variant_on_alias(ty, None, mod_path);
};
@@ -1630,6 +1630,10 @@ impl<'a> InferenceContext<'a> {
(ty, variant)
}
TypeNs::TypeAliasId(it) => {
+ let Some(mod_path) = path.mod_path() else {
+ never!("resolver should always resolve lang item paths");
+ return (self.err_ty(), None);
+ };
let substs = path_ctx.substs_from_path_segment(it.into(), true, None);
drop(ctx);
let ty = self.db.ty(it.into());
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index afa1f6dcc8..651ec151d4 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -570,10 +570,17 @@ impl AnyDiagnostic {
source_map: &hir_def::expr_store::BodySourceMap,
) -> Option<AnyDiagnostic> {
let expr_syntax = |expr| {
- source_map.expr_syntax(expr).inspect_err(|_| stdx::never!("synthetic syntax")).ok()
+ source_map
+ .expr_syntax(expr)
+ .inspect_err(|_| stdx::never!("inference diagnostic in desugared expr"))
+ .ok()
+ };
+ let pat_syntax = |pat| {
+ source_map
+ .pat_syntax(pat)
+ .inspect_err(|_| stdx::never!("inference diagnostic in desugared pattern"))
+ .ok()
};
- let pat_syntax =
- |pat| source_map.pat_syntax(pat).inspect_err(|_| stdx::never!("synthetic syntax")).ok();
let expr_or_pat_syntax = |id| match id {
ExprOrPatId::ExprId(expr) => expr_syntax(expr),
ExprOrPatId::PatId(pat) => pat_syntax(pat),
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 7d855cf449..13b161e59d 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -753,7 +753,7 @@ impl Analysis {
frange: FileRange,
) -> Cancellable<Vec<Assist>> {
let include_fixes = match &assist_config.allowed {
- Some(it) => it.iter().any(|&it| it == AssistKind::QuickFix),
+ Some(it) => it.contains(&AssistKind::QuickFix),
None => true,
};
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index 4841f48659..a9ed1857de 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -161,6 +161,7 @@ define_symbols! {
bitxor_assign,
bitxor,
bool,
+ bootstrap,
box_free,
Box,
boxed,
@@ -525,4 +526,8 @@ define_symbols! {
ignore_flyimport,
ignore_flyimport_methods,
ignore_methods,
+ position,
+ flags,
+ precision,
+ width,
}
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index a0fb4a7d0f..7a139ea0c4 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -1664,6 +1664,7 @@ fn sysroot_to_crate_graph(
vec![
CfgAtom::Flag(sym::debug_assertions.clone()),
CfgAtom::Flag(sym::miri.clone()),
+ CfgAtom::Flag(sym::bootstrap.clone()),
],
vec![CfgAtom::Flag(sym::test.clone())],
),