fix: Fix format_args lowering for >=1.87

This commit is contained in:
Lukas Wirth 2025-04-06 09:32:54 +02:00
parent 55c8cdeafb
commit e7ce86ddea
7 changed files with 128 additions and 53 deletions

View file

@ -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))
}

View file

@ -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(),
}
};
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),
)));
self.alloc_expr_desugared(Expr::Call {
callee: format_placeholder_new,
args: Box::new([position, fill, align, flags, precision, width]),
})
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.

View file

@ -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());

View file

@ -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),

View file

@ -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,
};

View file

@ -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,
}

View file

@ -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())],
),