Merge pull request #19330 from ChayimFriedman2/normalize-projection

fix: Normalize projections in evaluated const display and layout calculation
This commit is contained in:
Lukas Wirth 2025-03-10 09:15:35 +00:00 committed by GitHub
commit 27a5b1ba0c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 887 additions and 521 deletions

View file

@ -15,9 +15,10 @@ use stdx::never;
use triomphe::Arc;
use crate::{
db::HirDatabase, generics::Generics, infer::InferenceContext, lower::ParamLoweringMode,
mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData, ConstScalar, ConstValue,
GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder,
db::HirDatabase, display::DisplayTarget, generics::Generics, infer::InferenceContext,
lower::ParamLoweringMode, mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData,
ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty,
TyBuilder,
};
use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
@ -62,11 +63,15 @@ impl ConstEvalError {
f: &mut String,
db: &dyn HirDatabase,
span_formatter: impl Fn(span::FileId, span::TextRange) -> String,
edition: span::Edition,
display_target: DisplayTarget,
) -> std::result::Result<(), std::fmt::Error> {
match self {
ConstEvalError::MirLowerError(e) => e.pretty_print(f, db, span_formatter, edition),
ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter, edition),
ConstEvalError::MirLowerError(e) => {
e.pretty_print(f, db, span_formatter, display_target)
}
ConstEvalError::MirEvalError(e) => {
e.pretty_print(f, db, span_formatter, display_target)
}
}
}
}

View file

@ -10,8 +10,8 @@ use test_fixture::WithFixture;
use test_utils::skip_slow_tests;
use crate::{
consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar,
Interner, MemoryMap,
consteval::try_const_usize, db::HirDatabase, display::DisplayTarget, mir::pad16,
test_db::TestDB, Const, ConstScalar, Interner, MemoryMap,
};
use super::{
@ -101,11 +101,17 @@ fn check_answer(
fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
let mut err = String::new();
let span_formatter = |file, range| format!("{file:?} {range:?}");
let edition =
db.crate_graph()[*db.crate_graph().crates_in_topological_order().last().unwrap()].edition;
let display_target = DisplayTarget::from_crate(
&db,
*db.crate_graph().crates_in_topological_order().last().unwrap(),
);
match e {
ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
ConstEvalError::MirLowerError(e) => {
e.pretty_print(&mut err, &db, span_formatter, display_target)
}
ConstEvalError::MirEvalError(e) => {
e.pretty_print(&mut err, &db, span_formatter, display_target)
}
}
.unwrap();
err

View file

@ -16,7 +16,6 @@ use intern::sym;
use itertools::Itertools;
use rustc_hash::FxHashSet;
use rustc_pattern_analysis::constructor::Constructor;
use span::Edition;
use syntax::{
ast::{self, UnaryOp},
AstNode,
@ -31,7 +30,7 @@ use crate::{
self,
pat_analysis::{self, DeconstructedPat, MatchCheckCtx, WitnessPat},
},
display::HirDisplay,
display::{DisplayTarget, HirDisplay},
Adjust, InferenceResult, Interner, Ty, TyExt, TyKind,
};
@ -633,24 +632,24 @@ fn missing_match_arms<'p>(
arms_is_empty: bool,
krate: CrateId,
) -> String {
struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, Edition);
struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, DisplayTarget);
impl fmt::Display for DisplayWitness<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let DisplayWitness(witness, cx, edition) = *self;
let DisplayWitness(witness, cx, display_target) = *self;
let pat = cx.hoist_witness_pat(witness);
write!(f, "{}", pat.display(cx.db, edition))
write!(f, "{}", pat.display(cx.db, display_target))
}
}
let edition = cx.db.crate_graph()[krate].edition;
let non_empty_enum = match scrut_ty.as_adt() {
Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
_ => false,
};
let display_target = DisplayTarget::from_crate(cx.db, krate);
if arms_is_empty && !non_empty_enum {
format!("type `{}` is non-empty", scrut_ty.display(cx.db, edition))
format!("type `{}` is non-empty", scrut_ty.display(cx.db, display_target))
} else {
let pat_display = |witness| DisplayWitness(witness, cx, edition);
let pat_display = |witness| DisplayWitness(witness, cx, display_target);
const LIMIT: usize = 3;
match &*witnesses {
[witness] => format!("`{}` not covered", pat_display(witness)),

View file

@ -45,6 +45,7 @@ use crate::{
db::{HirDatabase, InternedClosure},
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
generics::generics,
infer::normalize,
layout::Layout,
lt_from_placeholder_idx,
mapping::from_chalk,
@ -87,6 +88,7 @@ pub struct HirFormatter<'a> {
show_container_bounds: bool,
omit_verbose_types: bool,
closure_style: ClosureStyle,
display_kind: DisplayKind,
display_target: DisplayTarget,
bounds_formatting_ctx: BoundsFormattingCtx,
}
@ -164,6 +166,7 @@ pub trait HirDisplay {
limited_size: Option<usize>,
omit_verbose_types: bool,
display_target: DisplayTarget,
display_kind: DisplayKind,
closure_style: ClosureStyle,
show_container_bounds: bool,
) -> HirDisplayWrapper<'a, Self>
@ -171,7 +174,7 @@ pub trait HirDisplay {
Self: Sized,
{
assert!(
!matches!(display_target, DisplayTarget::SourceCode { .. }),
!matches!(display_kind, DisplayKind::SourceCode { .. }),
"HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
);
HirDisplayWrapper {
@ -181,6 +184,7 @@ pub trait HirDisplay {
limited_size,
omit_verbose_types,
display_target,
display_kind,
closure_style,
show_container_bounds,
}
@ -191,7 +195,7 @@ pub trait HirDisplay {
fn display<'a>(
&'a self,
db: &'a dyn HirDatabase,
edition: Edition,
display_target: DisplayTarget,
) -> HirDisplayWrapper<'a, Self>
where
Self: Sized,
@ -203,7 +207,8 @@ pub trait HirDisplay {
limited_size: None,
omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics { edition },
display_target,
display_kind: DisplayKind::Diagnostics,
show_container_bounds: false,
}
}
@ -214,7 +219,7 @@ pub trait HirDisplay {
&'a self,
db: &'a dyn HirDatabase,
max_size: Option<usize>,
edition: Edition,
display_target: DisplayTarget,
) -> HirDisplayWrapper<'a, Self>
where
Self: Sized,
@ -226,7 +231,8 @@ pub trait HirDisplay {
limited_size: None,
omit_verbose_types: true,
closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics { edition },
display_target,
display_kind: DisplayKind::Diagnostics,
show_container_bounds: false,
}
}
@ -237,7 +243,7 @@ pub trait HirDisplay {
&'a self,
db: &'a dyn HirDatabase,
limited_size: Option<usize>,
edition: Edition,
display_target: DisplayTarget,
) -> HirDisplayWrapper<'a, Self>
where
Self: Sized,
@ -249,7 +255,8 @@ pub trait HirDisplay {
limited_size,
omit_verbose_types: true,
closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics { edition },
display_target,
display_kind: DisplayKind::Diagnostics,
show_container_bounds: false,
}
}
@ -272,7 +279,8 @@ pub trait HirDisplay {
entity_limit: None,
omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
display_target: DisplayTarget::from_crate(db, module_id.krate()),
display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque },
show_container_bounds: false,
bounds_formatting_ctx: Default::default(),
}) {
@ -284,29 +292,10 @@ pub trait HirDisplay {
}
/// Returns a String representation of `self` for test purposes
fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
where
Self: Sized,
{
HirDisplayWrapper {
db,
t: self,
max_size: None,
limited_size: None,
omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Test,
show_container_bounds: false,
}
}
/// Returns a String representation of `self` that shows the constraint from
/// the container for functions
fn display_with_container_bounds<'a>(
fn display_test<'a>(
&'a self,
db: &'a dyn HirDatabase,
show_container_bounds: bool,
edition: Edition,
display_target: DisplayTarget,
) -> HirDisplayWrapper<'a, Self>
where
Self: Sized,
@ -318,21 +307,44 @@ pub trait HirDisplay {
limited_size: None,
omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics { edition },
display_target,
display_kind: DisplayKind::Test,
show_container_bounds: false,
}
}
/// Returns a String representation of `self` that shows the constraint from
/// the container for functions
fn display_with_container_bounds<'a>(
&'a self,
db: &'a dyn HirDatabase,
show_container_bounds: bool,
display_target: DisplayTarget,
) -> HirDisplayWrapper<'a, Self>
where
Self: Sized,
{
HirDisplayWrapper {
db,
t: self,
max_size: None,
limited_size: None,
omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn,
display_target,
display_kind: DisplayKind::Diagnostics,
show_container_bounds,
}
}
}
impl HirFormatter<'_> {
pub fn krate(&self) -> CrateId {
self.display_target.krate
}
pub fn edition(&self) -> Edition {
match self.display_target {
DisplayTarget::Diagnostics { edition } => edition,
DisplayTarget::SourceCode { module_id, .. } => {
self.db.crate_graph()[module_id.krate()].edition
}
DisplayTarget::Test => Edition::CURRENT,
}
self.display_target.edition
}
pub fn write_joined<T: HirDisplay>(
@ -394,20 +406,33 @@ impl HirFormatter<'_> {
}
}
#[derive(Debug, Clone, Copy)]
pub struct DisplayTarget {
krate: CrateId,
pub edition: Edition,
}
impl DisplayTarget {
pub fn from_crate(db: &dyn HirDatabase, krate: CrateId) -> Self {
let edition = db.crate_graph()[krate].edition;
Self { krate, edition }
}
}
#[derive(Clone, Copy)]
pub enum DisplayTarget {
pub enum DisplayKind {
/// Display types for inlays, doc popups, autocompletion, etc...
/// Showing `{unknown}` or not qualifying paths is fine here.
/// There's no reason for this to fail.
Diagnostics { edition: Edition },
Diagnostics,
/// Display types for inserting them in source files.
/// The generated code should compile, so paths need to be qualified.
SourceCode { module_id: ModuleId, allow_opaque: bool },
SourceCode { target_module_id: ModuleId, allow_opaque: bool },
/// Only for test purpose to keep real types
Test,
}
impl DisplayTarget {
impl DisplayKind {
fn is_source_code(self) -> bool {
matches!(self, Self::SourceCode { .. })
}
@ -450,6 +475,7 @@ pub struct HirDisplayWrapper<'a, T> {
limited_size: Option<usize>,
omit_verbose_types: bool,
closure_style: ClosureStyle,
display_kind: DisplayKind,
display_target: DisplayTarget,
show_container_bounds: bool,
}
@ -479,6 +505,7 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
max_size: self.max_size,
entity_limit: self.limited_size,
omit_verbose_types: self.omit_verbose_types,
display_kind: self.display_kind,
display_target: self.display_target,
closure_style: self.closure_style,
show_container_bounds: self.show_container_bounds,
@ -533,7 +560,7 @@ impl HirDisplay for ProjectionTy {
// if we are projection on a type parameter, check if the projection target has bounds
// itself, if so, we render them directly as `impl Bound` instead of the less useful
// `<Param as Trait>::Assoc`
if !f.display_target.is_source_code() {
if !f.display_kind.is_source_code() {
if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
if !f.bounds_formatting_ctx.contains(self) {
let db = f.db;
@ -653,10 +680,8 @@ fn render_const_scalar(
memory_map: &MemoryMap,
ty: &Ty,
) -> Result<(), HirDisplayError> {
// FIXME: We need to get krate from the final callers of the hir display
// infrastructure and have it here as a field on `f`.
let trait_env =
TraitEnvironment::empty(*f.db.crate_graph().crates_in_topological_order().last().unwrap());
let trait_env = TraitEnvironment::empty(f.krate());
let ty = normalize(f.db, trait_env.clone(), ty.clone());
match ty.kind(Interner) {
TyKind::Scalar(s) => match s {
Scalar::Bool => write!(f, "{}", b[0] != 0),
@ -1109,7 +1134,7 @@ impl HirDisplay for Ty {
let def = from_chalk(db, *def);
let sig = db.callable_item_signature(def).substitute(Interner, parameters);
if f.display_target.is_source_code() {
if f.display_kind.is_source_code() {
// `FnDef` is anonymous and there's no surface syntax for it. Show it as a
// function pointer type.
return sig.hir_fmt(f);
@ -1198,8 +1223,8 @@ impl HirDisplay for Ty {
}
TyKind::Adt(AdtId(def_id), parameters) => {
f.start_location_link((*def_id).into());
match f.display_target {
DisplayTarget::Diagnostics { .. } | DisplayTarget::Test => {
match f.display_kind {
DisplayKind::Diagnostics { .. } | DisplayKind::Test { .. } => {
let name = match *def_id {
hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
@ -1207,7 +1232,7 @@ impl HirDisplay for Ty {
};
write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
}
DisplayTarget::SourceCode { module_id, allow_opaque: _ } => {
DisplayKind::SourceCode { target_module_id: module_id, allow_opaque: _ } => {
if let Some(path) = find_path::find_path(
db.upcast(),
ItemInNs::Types((*def_id).into()),
@ -1246,7 +1271,7 @@ impl HirDisplay for Ty {
let type_alias_data = db.type_alias_data(type_alias);
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
if f.display_target.is_test() {
if f.display_kind.is_test() {
f.start_location_link(trait_.into());
write!(f, "{}", trait_data.name.display(f.db.upcast(), f.edition()))?;
f.end_location_link();
@ -1275,7 +1300,7 @@ impl HirDisplay for Ty {
f.end_location_link();
}
TyKind::OpaqueType(opaque_ty_id, parameters) => {
if !f.display_target.allows_opaque() {
if !f.display_kind.allows_opaque() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::OpaqueType,
));
@ -1344,8 +1369,8 @@ impl HirDisplay for Ty {
}
}
TyKind::Closure(id, substs) => {
if f.display_target.is_source_code() {
if !f.display_target.allows_opaque() {
if f.display_kind.is_source_code() {
if !f.display_kind.allows_opaque() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::OpaqueType,
));
@ -1465,7 +1490,7 @@ impl HirDisplay for Ty {
}
TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
if !f.display_target.allows_opaque() {
if !f.display_kind.allows_opaque() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::OpaqueType,
));
@ -1508,7 +1533,7 @@ impl HirDisplay for Ty {
};
}
TyKind::Error => {
if f.display_target.is_source_code() {
if f.display_kind.is_source_code() {
f.write_char('_')?;
} else {
write!(f, "{{unknown}}")?;
@ -1516,7 +1541,7 @@ impl HirDisplay for Ty {
}
TyKind::InferenceVar(..) => write!(f, "_")?,
TyKind::Coroutine(_, subst) => {
if f.display_target.is_source_code() {
if f.display_kind.is_source_code() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::Coroutine,
));
@ -1573,7 +1598,7 @@ fn generic_args_sans_defaults<'ga>(
generic_def: Option<hir_def::GenericDefId>,
parameters: &'ga [GenericArg],
) -> &'ga [GenericArg] {
if f.display_target.is_source_code() || f.omit_verbose_types() {
if f.display_kind.is_source_code() || f.omit_verbose_types() {
match generic_def
.map(|generic_def_id| f.db.generic_defaults(generic_def_id))
.filter(|it| !it.is_empty())
@ -1958,7 +1983,7 @@ impl HirDisplay for LifetimeData {
write!(f, "{}", param_data.name.display(f.db.upcast(), f.edition()))?;
Ok(())
}
_ if f.display_target.is_source_code() => write!(f, "'_"),
_ if f.display_kind.is_source_code() => write!(f, "'_"),
LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
LifetimeData::InferenceVar(_) => write!(f, "_"),
LifetimeData::Static => write!(f, "'static"),

View file

@ -435,6 +435,9 @@ pub fn layout_of_ty_query(
TyKind::Error => return Err(LayoutError::HasErrorType),
TyKind::AssociatedType(id, subst) => {
// Try again with `TyKind::Alias` to normalize the associated type.
// Usually we should not try to normalize `TyKind::AssociatedType`, but layout calculation is used
// in monomorphized MIR where this is okay. If outside monomorphization, this will lead to cycle,
// which we will recover from with an error.
let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
associated_ty_id: *id,
substitution: subst.clone(),

View file

@ -76,13 +76,15 @@ use intern::{sym, Symbol};
use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap};
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
use span::Edition;
use syntax::ast::{make, ConstArg};
use traits::FnTrait;
use triomphe::Arc;
use crate::{
consteval::unknown_const, db::HirDatabase, display::HirDisplay, generics::Generics,
consteval::unknown_const,
db::HirDatabase,
display::{DisplayTarget, HirDisplay},
generics::Generics,
infer::unify::InferenceTable,
};
@ -1044,7 +1046,7 @@ where
pub fn known_const_to_ast(
konst: &Const,
db: &dyn HirDatabase,
edition: Edition,
display_target: DisplayTarget,
) -> Option<ConstArg> {
if let ConstValue::Concrete(c) = &konst.interned().value {
match c.interned {
@ -1055,7 +1057,7 @@ pub fn known_const_to_ast(
_ => (),
}
}
Some(make::expr_const_value(konst.display(db, edition).to_string().as_str()))
Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str()))
}
#[derive(Debug, Copy, Clone)]

View file

@ -5,7 +5,7 @@ use std::{collections::hash_map::Entry, fmt::Display, iter};
use crate::{
consteval::usize_const,
db::HirDatabase,
display::HirDisplay,
display::{DisplayTarget, HirDisplay},
infer::{normalize, PointerCast},
lang_items::is_box,
mapping::ToChalk,
@ -168,7 +168,7 @@ impl<V, T> ProjectionElem<V, T> {
_ => {
never!(
"Overloaded deref on type {} is not a projection",
base.display(db, db.crate_graph()[krate].edition)
base.display(db, DisplayTarget::from_crate(db, krate))
);
TyKind::Error.intern(Interner)
}

View file

@ -13,6 +13,7 @@ use triomphe::Arc;
use crate::{
db::{HirDatabase, InternedClosure},
display::DisplayTarget,
mir::Operand,
utils::ClosureSubst,
ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags,
@ -422,7 +423,10 @@ fn ever_initialized_map(
let Some(terminator) = &block.terminator else {
never!(
"Terminator should be none only in construction.\nThe body:\n{}",
body.pretty_print(db)
body.pretty_print(
db,
DisplayTarget::from_crate(db, body.owner.krate(db.upcast()))
)
);
return;
};

View file

@ -24,7 +24,7 @@ use rustc_apfloat::{
Float,
};
use rustc_hash::{FxHashMap, FxHashSet};
use span::{Edition, FileId};
use span::FileId;
use stdx::never;
use syntax::{SyntaxNodePtr, TextRange};
use triomphe::Arc;
@ -32,7 +32,7 @@ use triomphe::Arc;
use crate::{
consteval::{intern_const_scalar, try_const_usize, ConstEvalError},
db::{HirDatabase, InternedClosure},
display::{ClosureStyle, HirDisplay},
display::{ClosureStyle, DisplayTarget, HirDisplay},
infer::PointerCast,
layout::{Layout, LayoutError, RustcEnumVariantIdx},
mapping::from_chalk,
@ -359,7 +359,7 @@ impl MirEvalError {
f: &mut String,
db: &dyn HirDatabase,
span_formatter: impl Fn(FileId, TextRange) -> String,
edition: Edition,
display_target: DisplayTarget,
) -> std::result::Result<(), std::fmt::Error> {
writeln!(f, "Mir eval error:")?;
let mut err = self;
@ -372,7 +372,7 @@ impl MirEvalError {
writeln!(
f,
"In function {} ({:?})",
function_name.name.display(db.upcast(), edition),
function_name.name.display(db.upcast(), display_target.edition),
func
)?;
}
@ -417,7 +417,7 @@ impl MirEvalError {
write!(
f,
"Layout for type `{}` is not available due {err:?}",
ty.display(db, edition).with_closure_style(ClosureStyle::ClosureWithId)
ty.display(db, display_target).with_closure_style(ClosureStyle::ClosureWithId)
)?;
}
MirEvalError::MirLowerError(func, err) => {
@ -428,12 +428,15 @@ impl MirEvalError {
let substs = generics.placeholder_subst(db);
db.impl_self_ty(impl_id)
.substitute(Interner, &substs)
.display(db, edition)
.display(db, display_target)
.to_string()
}),
ItemContainerId::TraitId(it) => {
Some(db.trait_data(it).name.display(db.upcast(), edition).to_string())
}
ItemContainerId::TraitId(it) => Some(
db.trait_data(it)
.name
.display(db.upcast(), display_target.edition)
.to_string(),
),
_ => None,
};
writeln!(
@ -441,17 +444,17 @@ impl MirEvalError {
"MIR lowering for function `{}{}{}` ({:?}) failed due:",
self_.as_deref().unwrap_or_default(),
if self_.is_some() { "::" } else { "" },
function_name.name.display(db.upcast(), edition),
function_name.name.display(db.upcast(), display_target.edition),
func
)?;
err.pretty_print(f, db, span_formatter, edition)?;
err.pretty_print(f, db, span_formatter, display_target)?;
}
MirEvalError::ConstEvalError(name, err) => {
MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
f,
db,
span_formatter,
edition,
display_target,
)?;
}
MirEvalError::UndefinedBehavior(_)

View file

@ -14,6 +14,7 @@ use intern::{sym, Symbol};
use stdx::never;
use crate::{
display::DisplayTarget,
error_lifetime,
mir::eval::{
pad16, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, HirDisplay,
@ -835,8 +836,7 @@ impl Evaluator<'_> {
// render full paths.
Err(_) => {
let krate = locals.body.owner.krate(self.db.upcast());
let edition = self.db.crate_graph()[krate].edition;
ty.display(self.db, edition).to_string()
ty.display(self.db, DisplayTarget::from_crate(self.db, krate)).to_string()
}
};
let len = ty_name.len();

View file

@ -3,6 +3,7 @@ use span::{Edition, EditionedFileId};
use syntax::{TextRange, TextSize};
use test_fixture::WithFixture;
use crate::display::DisplayTarget;
use crate::{db::HirDatabase, mir::MirLowerError, test_db::TestDB, Interner, Substitution};
use super::{interpret_mir, MirEvalError};
@ -67,7 +68,9 @@ fn check_pass_and_stdio(
let span_formatter = |file, range: TextRange| {
format!("{:?} {:?}..{:?}", file, line_index(range.start()), line_index(range.end()))
};
e.pretty_print(&mut err, &db, span_formatter, Edition::CURRENT).unwrap();
let krate = db.module_for_file(file_id).krate();
e.pretty_print(&mut err, &db, span_formatter, DisplayTarget::from_crate(&db, krate))
.unwrap();
panic!("Error in interpreting: {err}");
}
Ok((stdout, stderr)) => {

View file

@ -2,7 +2,7 @@
use std::{fmt::Write, iter, mem};
use base_db::ra_salsa::Cycle;
use base_db::{ra_salsa::Cycle, CrateId};
use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
use hir_def::{
data::adt::{StructKind, VariantData},
@ -29,7 +29,7 @@ use triomphe::Arc;
use crate::{
consteval::ConstEvalError,
db::{HirDatabase, InternedClosure},
display::{hir_display_with_types_map, HirDisplay},
display::{hir_display_with_types_map, DisplayTarget, HirDisplay},
error_lifetime,
generics::generics,
infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch},
@ -160,17 +160,17 @@ impl MirLowerError {
f: &mut String,
db: &dyn HirDatabase,
span_formatter: impl Fn(FileId, TextRange) -> String,
edition: Edition,
display_target: DisplayTarget,
) -> std::result::Result<(), std::fmt::Error> {
match self {
MirLowerError::ConstEvalError(name, e) => {
writeln!(f, "In evaluating constant {name}")?;
match &**e {
ConstEvalError::MirLowerError(e) => {
e.pretty_print(f, db, span_formatter, edition)?
e.pretty_print(f, db, span_formatter, display_target)?
}
ConstEvalError::MirEvalError(e) => {
e.pretty_print(f, db, span_formatter, edition)?
e.pretty_print(f, db, span_formatter, display_target)?
}
}
}
@ -179,15 +179,15 @@ impl MirLowerError {
writeln!(
f,
"Missing function definition for {}",
body.pretty_print_expr(db.upcast(), *owner, *it, edition)
body.pretty_print_expr(db.upcast(), *owner, *it, display_target.edition)
)?;
}
MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?,
MirLowerError::TypeMismatch(e) => writeln!(
f,
"Type mismatch: Expected {}, found {}",
e.expected.display(db, edition),
e.actual.display(db, edition),
e.expected.display(db, display_target),
e.actual.display(db, display_target),
)?,
MirLowerError::GenericArgNotProvided(id, subst) => {
let parent = id.parent;
@ -195,11 +195,14 @@ impl MirLowerError {
writeln!(
f,
"Generic arg not provided for {}",
param.name().unwrap_or(&Name::missing()).display(db.upcast(), edition)
param
.name()
.unwrap_or(&Name::missing())
.display(db.upcast(), display_target.edition)
)?;
writeln!(f, "Provided args: [")?;
for g in subst.iter(Interner) {
write!(f, " {},", g.display(db, edition))?;
write!(f, " {},", g.display(db, display_target))?;
}
writeln!(f, "]")?;
}
@ -251,11 +254,11 @@ impl MirLowerError {
fn unresolved_path(
db: &dyn HirDatabase,
p: &Path,
edition: Edition,
display_target: DisplayTarget,
types_map: &TypesMap,
) -> Self {
Self::UnresolvedName(
hir_display_with_types_map(p, types_map).display(db, edition).to_string(),
hir_display_with_types_map(p, types_map).display(db, display_target).to_string(),
)
}
}
@ -462,7 +465,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
MirLowerError::unresolved_path(
self.db,
p,
self.edition(),
DisplayTarget::from_crate(self.db, self.krate()),
&self.body.types,
)
})?;
@ -838,7 +841,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
Some(p) => MirLowerError::UnresolvedName(
hir_display_with_types_map(&**p, &self.body.types)
.display(self.db, self.edition())
.display(self.db, self.display_target())
.to_string(),
),
None => MirLowerError::RecordLiteralWithoutPath,
@ -1362,9 +1365,16 @@ impl<'ctx> MirLowerCtx<'ctx> {
match &self.body.exprs[*loc] {
Expr::Literal(l) => self.lower_literal_to_operand(ty, l),
Expr::Path(c) => {
let edition = self.edition();
let unresolved_name =
|| MirLowerError::unresolved_path(self.db, c, edition, &self.body.types);
let owner = self.owner;
let db = self.db;
let unresolved_name = || {
MirLowerError::unresolved_path(
self.db,
c,
DisplayTarget::from_crate(db, owner.krate(db.upcast())),
&self.body.types,
)
};
let pr = self
.resolver
.resolve_path_in_value_ns(self.db.upcast(), c, HygieneId::ROOT)
@ -1910,8 +1920,15 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
fn edition(&self) -> Edition {
let krate = self.owner.krate(self.db.upcast());
self.db.crate_graph()[krate].edition
self.db.crate_graph()[self.krate()].edition
}
fn krate(&self) -> CrateId {
self.owner.krate(self.db.upcast())
}
fn display_target(&self) -> DisplayTarget {
DisplayTarget::from_crate(self.db, self.krate())
}
fn drop_until_scope(

View file

@ -350,7 +350,12 @@ impl MirLowerCtx<'_> {
)?,
None => {
let unresolved_name = || {
MirLowerError::unresolved_path(self.db, p, self.edition(), &self.body.types)
MirLowerError::unresolved_path(
self.db,
p,
self.display_target(),
&self.body.types,
)
};
let hygiene = self.body.pat_path_hygiene(pattern);
let pr = self

View file

@ -9,11 +9,10 @@ use either::Either;
use hir_def::{expr_store::Body, hir::BindingId};
use hir_expand::{name::Name, Lookup};
use la_arena::ArenaMap;
use span::Edition;
use crate::{
db::HirDatabase,
display::{ClosureStyle, HirDisplay},
display::{ClosureStyle, DisplayTarget, HirDisplay},
mir::{PlaceElem, ProjectionElem, StatementKind, TerminatorKind},
ClosureId,
};
@ -39,17 +38,21 @@ macro_rules! wln {
}
impl MirBody {
pub fn pretty_print(&self, db: &dyn HirDatabase) -> String {
pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String {
let hir_body = db.body(self.owner);
let mut ctx = MirPrettyCtx::new(self, &hir_body, db);
let mut ctx = MirPrettyCtx::new(self, &hir_body, db, display_target);
ctx.for_body(|this| match ctx.body.owner {
hir_def::DefWithBodyId::FunctionId(id) => {
let data = db.function_data(id);
w!(this, "fn {}() ", data.name.display(db.upcast(), Edition::LATEST));
w!(this, "fn {}() ", data.name.display(db.upcast(), this.display_target.edition));
}
hir_def::DefWithBodyId::StaticId(id) => {
let data = db.static_data(id);
w!(this, "static {}: _ = ", data.name.display(db.upcast(), Edition::LATEST));
w!(
this,
"static {}: _ = ",
data.name.display(db.upcast(), this.display_target.edition)
);
}
hir_def::DefWithBodyId::ConstId(id) => {
let data = db.const_data(id);
@ -59,7 +62,7 @@ impl MirBody {
data.name
.as_ref()
.unwrap_or(&Name::missing())
.display(db.upcast(), Edition::LATEST)
.display(db.upcast(), this.display_target.edition)
);
}
hir_def::DefWithBodyId::VariantId(id) => {
@ -70,10 +73,10 @@ impl MirBody {
"enum {}::{} = ",
enum_loc.id.item_tree(db.upcast())[enum_loc.id.value]
.name
.display(db.upcast(), Edition::LATEST),
.display(db.upcast(), this.display_target.edition),
loc.id.item_tree(db.upcast())[loc.id.value]
.name
.display(db.upcast(), Edition::LATEST),
.display(db.upcast(), this.display_target.edition),
)
}
hir_def::DefWithBodyId::InTypeConstId(id) => {
@ -85,14 +88,14 @@ impl MirBody {
// String with lines is rendered poorly in `dbg` macros, which I use very much, so this
// function exists to solve that.
pub fn dbg(&self, db: &dyn HirDatabase) -> impl Debug {
pub fn dbg(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> impl Debug {
struct StringDbg(String);
impl Debug for StringDbg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
StringDbg(self.pretty_print(db))
StringDbg(self.pretty_print(db, display_target))
}
}
@ -103,6 +106,7 @@ struct MirPrettyCtx<'a> {
result: String,
indent: String,
local_to_binding: ArenaMap<LocalId, BindingId>,
display_target: DisplayTarget,
}
impl Write for MirPrettyCtx<'_> {
@ -182,7 +186,12 @@ impl<'a> MirPrettyCtx<'a> {
wln!(self, "}}");
}
fn new(body: &'a MirBody, hir_body: &'a Body, db: &'a dyn HirDatabase) -> Self {
fn new(
body: &'a MirBody,
hir_body: &'a Body,
db: &'a dyn HirDatabase,
display_target: DisplayTarget,
) -> Self {
let local_to_binding = body.local_to_binding_map();
MirPrettyCtx {
body,
@ -191,6 +200,7 @@ impl<'a> MirPrettyCtx<'a> {
indent: String::new(),
local_to_binding,
hir_body,
display_target,
}
}
@ -208,7 +218,7 @@ impl<'a> MirPrettyCtx<'a> {
wln!(
self,
"let {}: {};",
self.local_name(id).display_test(self.db),
self.local_name(id).display_test(self.db, self.display_target),
self.hir_display(&local.ty)
);
}
@ -242,14 +252,14 @@ impl<'a> MirPrettyCtx<'a> {
wln!(
this,
"StorageDead({})",
this.local_name(*p).display_test(self.db)
this.local_name(*p).display_test(this.db, this.display_target)
);
}
StatementKind::StorageLive(p) => {
wln!(
this,
"StorageLive({})",
this.local_name(*p).display_test(self.db)
this.local_name(*p).display_test(this.db, this.display_target)
);
}
StatementKind::Deinit(p) => {
@ -313,7 +323,7 @@ impl<'a> MirPrettyCtx<'a> {
fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) {
let Some((last, head)) = projections.split_last() else {
// no projection
w!(this, "{}", this.local_name(local).display_test(this.db));
w!(this, "{}", this.local_name(local).display_test(this.db, this.display_target));
return;
};
match last {
@ -333,13 +343,17 @@ impl<'a> MirPrettyCtx<'a> {
w!(
this,
" as {}).{}",
variant_name.display(this.db.upcast(), Edition::LATEST),
name.display(this.db.upcast(), Edition::LATEST)
variant_name.display(this.db.upcast(), this.display_target.edition),
name.display(this.db.upcast(), this.display_target.edition)
);
}
hir_def::VariantId::StructId(_) | hir_def::VariantId::UnionId(_) => {
f(this, local, head);
w!(this, ".{}", name.display(this.db.upcast(), Edition::LATEST));
w!(
this,
".{}",
name.display(this.db.upcast(), this.display_target.edition)
);
}
}
}
@ -353,7 +367,11 @@ impl<'a> MirPrettyCtx<'a> {
}
ProjectionElem::Index(l) => {
f(this, local, head);
w!(this, "[{}]", this.local_name(*l).display_test(this.db));
w!(
this,
"[{}]",
this.local_name(*l).display_test(this.db, this.display_target)
);
}
it => {
f(this, local, head);
@ -403,7 +421,7 @@ impl<'a> MirPrettyCtx<'a> {
Rvalue::Repeat(op, len) => {
w!(self, "[");
self.operand(op);
w!(self, "; {}]", len.display_test(self.db));
w!(self, "; {}]", len.display_test(self.db, self.display_target));
}
Rvalue::Aggregate(AggregateKind::Adt(_, _), it) => {
w!(self, "Adt(");
@ -478,6 +496,7 @@ impl<'a> MirPrettyCtx<'a> {
}
fn hir_display<T: HirDisplay>(&self, ty: &'a T) -> impl Display + 'a {
ty.display_test(self.db).with_closure_style(ClosureStyle::ClosureWithSubst)
ty.display_test(self.db, self.display_target)
.with_closure_style(ClosureStyle::ClosureWithSubst)
}
}

View file

@ -15,7 +15,7 @@ mod type_alias_impl_traits;
use std::env;
use std::sync::LazyLock;
use base_db::SourceDatabaseFileInputExt as _;
use base_db::{CrateId, SourceDatabaseFileInputExt as _};
use expect_test::Expect;
use hir_def::{
db::DefDatabase,
@ -41,7 +41,7 @@ use triomphe::Arc;
use crate::{
db::HirDatabase,
display::HirDisplay,
display::{DisplayTarget, HirDisplay},
infer::{Adjustment, TypeMismatch},
test_db::TestDB,
InferenceResult, Ty,
@ -124,7 +124,7 @@ fn check_impl(
}
assert!(had_annotations || allow_none, "no `//^` annotations found");
let mut defs: Vec<DefWithBodyId> = Vec::new();
let mut defs: Vec<(DefWithBodyId, CrateId)> = Vec::new();
for file_id in files {
let module = db.module_for_file_opt(file_id);
let module = match module {
@ -133,16 +133,17 @@ fn check_impl(
};
let def_map = module.def_map(&db);
visit_module(&db, &def_map, module.local_id, &mut |it| {
defs.push(match it {
let def = match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
ModuleDefId::ConstId(it) => it.into(),
ModuleDefId::StaticId(it) => it.into(),
_ => return,
})
};
defs.push((def, module.krate()))
});
}
defs.sort_by_key(|def| match def {
defs.sort_by_key(|(def, _)| match def {
DefWithBodyId::FunctionId(it) => {
let loc = it.lookup(&db);
loc.source(&db).value.syntax().text_range().start()
@ -162,7 +163,8 @@ fn check_impl(
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
});
let mut unexpected_type_mismatches = String::new();
for def in defs {
for (def, krate) in defs {
let display_target = DisplayTarget::from_crate(&db, krate);
let (body, body_source_map) = db.body_with_source_map(def);
let inference_result = db.infer(def);
@ -179,7 +181,7 @@ fn check_impl(
let actual = if display_source {
ty.display_source_code(&db, def.module(&db), true).unwrap()
} else {
ty.display_test(&db).to_string()
ty.display_test(&db, display_target).to_string()
};
assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
}
@ -195,7 +197,7 @@ fn check_impl(
let actual = if display_source {
ty.display_source_code(&db, def.module(&db), true).unwrap()
} else {
ty.display_test(&db).to_string()
ty.display_test(&db, display_target).to_string()
};
assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
}
@ -224,8 +226,8 @@ fn check_impl(
let range = node.as_ref().original_file_range_rooted(&db);
let actual = format!(
"expected {}, got {}",
mismatch.expected.display_test(&db),
mismatch.actual.display_test(&db)
mismatch.expected.display_test(&db, display_target),
mismatch.actual.display_test(&db, display_target)
);
match mismatches.remove(&range) {
Some(annotation) => assert_eq!(actual, annotation),
@ -299,7 +301,9 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let mut infer_def = |inference_result: Arc<InferenceResult>,
body: Arc<Body>,
body_source_map: Arc<BodySourceMap>| {
body_source_map: Arc<BodySourceMap>,
krate: CrateId| {
let display_target = DisplayTarget::from_crate(&db, krate);
let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new();
let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch)> = Vec::new();
@ -361,7 +365,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
macro_prefix,
range,
ellipsize(text, 15),
ty.display_test(&db)
ty.display_test(&db, display_target)
);
}
if include_mismatches {
@ -377,8 +381,8 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
"{}{:?}: expected {}, got {}\n",
macro_prefix,
range,
mismatch.expected.display_test(&db),
mismatch.actual.display_test(&db),
mismatch.expected.display_test(&db, display_target),
mismatch.actual.display_test(&db, display_target),
);
}
}
@ -387,17 +391,18 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let module = db.module_for_file(file_id);
let def_map = module.def_map(&db);
let mut defs: Vec<DefWithBodyId> = Vec::new();
let mut defs: Vec<(DefWithBodyId, CrateId)> = Vec::new();
visit_module(&db, &def_map, module.local_id, &mut |it| {
defs.push(match it {
let def = match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
ModuleDefId::ConstId(it) => it.into(),
ModuleDefId::StaticId(it) => it.into(),
_ => return,
})
};
defs.push((def, module.krate()))
});
defs.sort_by_key(|def| match def {
defs.sort_by_key(|(def, _)| match def {
DefWithBodyId::FunctionId(it) => {
let loc = it.lookup(&db);
loc.source(&db).value.syntax().text_range().start()
@ -416,10 +421,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
}
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
});
for def in defs {
for (def, krate) in defs {
let (body, source_map) = db.body_with_source_map(def);
let infer = db.infer(def);
infer_def(infer, body, source_map);
infer_def(infer, body, source_map, krate);
}
buf.truncate(buf.trim_end().len());

View file

@ -8,7 +8,7 @@ use syntax::{AstNode, AstPtr};
use test_fixture::WithFixture;
use crate::db::{HirDatabase, InternedClosureId};
use crate::display::HirDisplay;
use crate::display::{DisplayTarget, HirDisplay};
use crate::mir::MirSpan;
use crate::test_db::TestDB;
@ -66,7 +66,11 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
.join(", "),
};
let place = capture.display_place(closure.0, db);
let capture_ty = capture.ty.skip_binders().display_test(db).to_string();
let capture_ty = capture
.ty
.skip_binders()
.display_test(db, DisplayTarget::from_crate(db, module.krate()))
.to_string();
let spans = capture
.spans()
.iter()