Skip to content

Render more lifetimes #19581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 61 additions & 8 deletions crates/hir-ty/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,26 @@ pub struct HirFormatter<'a> {
show_container_bounds: bool,
omit_verbose_types: bool,
closure_style: ClosureStyle,
display_lifetimes: DisplayLifetime,
display_kind: DisplayKind,
display_target: DisplayTarget,
bounds_formatting_ctx: BoundsFormattingCtx,
}

// FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should
// not be when in signatures
// So this enum does not encode this well enough
// Also 'static can be omitted for ref and dyn trait lifetimes in static/const item types
// FIXME: Also named lifetimes may be rendered in places where their name is not in scope?
#[derive(Copy, Clone)]
pub enum DisplayLifetime {
Always,
OnlyStatic,
OnlyNamed,
OnlyNamedOrStatic,
Never,
}

#[derive(Default)]
enum BoundsFormattingCtx {
Entered {
Expand Down Expand Up @@ -156,6 +171,21 @@ impl HirFormatter<'_> {
}
}
}

fn render_lifetime(&self, lifetime: &Lifetime) -> bool {
match self.display_lifetimes {
DisplayLifetime::Always => true,
DisplayLifetime::OnlyStatic => matches!(***lifetime.interned(), LifetimeData::Static),
DisplayLifetime::OnlyNamed => {
matches!(***lifetime.interned(), LifetimeData::Placeholder(_))
}
DisplayLifetime::OnlyNamedOrStatic => matches!(
***lifetime.interned(),
LifetimeData::Static | LifetimeData::Placeholder(_)
),
DisplayLifetime::Never => false,
}
}
}

pub trait HirDisplay {
Expand Down Expand Up @@ -190,6 +220,7 @@ pub trait HirDisplay {
display_kind,
closure_style,
show_container_bounds,
display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
}
}

Expand All @@ -213,6 +244,7 @@ pub trait HirDisplay {
display_target,
display_kind: DisplayKind::Diagnostics,
show_container_bounds: false,
display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
}
}

Expand All @@ -237,6 +269,7 @@ pub trait HirDisplay {
display_target,
display_kind: DisplayKind::Diagnostics,
show_container_bounds: false,
display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
}
}

Expand All @@ -261,6 +294,7 @@ pub trait HirDisplay {
display_target,
display_kind: DisplayKind::Diagnostics,
show_container_bounds: false,
display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
}
}

Expand All @@ -285,6 +319,7 @@ pub trait HirDisplay {
display_target: DisplayTarget::from_crate(db, module_id.krate()),
display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque },
show_container_bounds: false,
display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
bounds_formatting_ctx: Default::default(),
}) {
Ok(()) => {}
Expand Down Expand Up @@ -313,6 +348,7 @@ pub trait HirDisplay {
display_target,
display_kind: DisplayKind::Test,
show_container_bounds: false,
display_lifetimes: DisplayLifetime::Always,
}
}

Expand All @@ -337,6 +373,7 @@ pub trait HirDisplay {
display_target,
display_kind: DisplayKind::Diagnostics,
show_container_bounds,
display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
}
}
}
Expand Down Expand Up @@ -481,6 +518,7 @@ pub struct HirDisplayWrapper<'a, T> {
display_kind: DisplayKind,
display_target: DisplayTarget,
show_container_bounds: bool,
display_lifetimes: DisplayLifetime,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Expand All @@ -503,7 +541,7 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
self.t.hir_fmt(&mut HirFormatter {
db: self.db,
fmt: f,
buf: String::with_capacity(20),
buf: String::with_capacity(self.max_size.unwrap_or(20)),
curr_size: 0,
max_size: self.max_size,
entity_limit: self.limited_size,
Expand All @@ -512,6 +550,7 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
display_target: self.display_target,
closure_style: self.closure_style,
show_container_bounds: self.show_container_bounds,
display_lifetimes: self.display_lifetimes,
bounds_formatting_ctx: Default::default(),
})
}
Expand All @@ -520,6 +559,11 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
self.closure_style = c;
self
}

pub fn with_lifetime_display(mut self, l: DisplayLifetime) -> Self {
self.display_lifetimes = l;
self
}
}

impl<T> fmt::Display for HirDisplayWrapper<'_, T>
Expand Down Expand Up @@ -1024,9 +1068,7 @@ impl HirDisplay for Ty {
kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => {
if let TyKind::Ref(_, l, _) = kind {
f.write_char('&')?;
if cfg!(test) {
// rendering these unconditionally is probably too much (at least for inlay
// hints) so we gate it to testing only for the time being
if f.render_lifetime(l) {
l.hir_fmt(f)?;
f.write_char(' ')?;
}
Expand Down Expand Up @@ -1057,9 +1099,10 @@ impl HirDisplay for Ty {
})
};
let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) {
TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
TyKind::Dyn(dyn_ty) => {
let bounds = dyn_ty.bounds.skip_binders().interned();
(bounds.len(), contains_impl_fn(bounds))
let render_lifetime = f.render_lifetime(&dyn_ty.lifetime);
(bounds.len() + render_lifetime as usize, contains_impl_fn(bounds))
}
TyKind::Alias(AliasTy::Opaque(OpaqueTy {
opaque_ty_id,
Expand Down Expand Up @@ -1479,7 +1522,7 @@ impl HirDisplay for Ty {
TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
TyKind::Dyn(dyn_ty) => {
// Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
// FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it
// FIXME: `Iterator::partition_in_place()` or `Vec::extract_if()` may make it
// more efficient when either of them hits stable.
let mut bounds: SmallVec<[_; 4]> =
dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
Expand All @@ -1488,6 +1531,17 @@ impl HirDisplay for Ty {
bounds.extend(others);
bounds.extend(auto_traits);

if f.render_lifetime(&dyn_ty.lifetime) {
// we skip the binders in `write_bounds_like_dyn_trait_with_prefix`
bounds.push(Binders::empty(
Interner,
chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
ty: self.clone(),
lifetime: dyn_ty.lifetime.clone(),
}),
));
}

write_bounds_like_dyn_trait_with_prefix(
f,
"dyn",
Expand Down Expand Up @@ -1991,7 +2045,6 @@ impl HirDisplay for LifetimeData {
write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
Ok(())
}
_ 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"),
Expand Down
6 changes: 3 additions & 3 deletions crates/hir-ty/src/tests/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ trait Foo {}
fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
let _: &dyn Foo = &f;
let _: &dyn Foo = g;
//^ expected &'? dyn Foo, got &'? impl Foo + ?Sized
//^ expected &'? (dyn Foo + 'static), got &'? impl Foo + ?Sized
}
"#,
);
Expand Down Expand Up @@ -827,11 +827,11 @@ struct V<T> { t: T }
fn main() {
let a: V<&dyn Tr>;
(a,) = V { t: &S };
//^^^^expected V<&'? S>, got (V<&'? dyn Tr>,)
//^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,)

let mut a: V<&dyn Tr> = V { t: &S };
(a,) = V { t: &S };
//^^^^expected V<&'? S>, got (V<&'? dyn Tr>,)
//^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,)
}
"#,
);
Expand Down
18 changes: 9 additions & 9 deletions crates/hir-ty/src/tests/display_source_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ trait A {
}
trait B: A {}

fn test(
fn test<'a>(
_: &(dyn A<Assoc = ()> + Send),
//^ &'_ (dyn A<Assoc = ()> + Send)
_: &(dyn Send + A<Assoc = ()>),
//^ &'_ (dyn A<Assoc = ()> + Send)
//^ &(dyn A<Assoc = ()> + Send + 'static)
_: &'a (dyn Send + A<Assoc = ()>),
//^ &'a (dyn A<Assoc = ()> + Send + 'static)
_: &dyn B<Assoc = ()>,
//^ &'_ (dyn B<Assoc = ()>)
//^ &(dyn B<Assoc = ()> + 'static)
) {}
"#,
);
Expand All @@ -85,7 +85,7 @@ fn render_dyn_for_ty() {
trait Foo<'a> {}

fn foo(foo: &dyn for<'a> Foo<'a>) {}
// ^^^ &'_ dyn Foo<'_>
// ^^^ &(dyn Foo<'_> + '_)
"#,
);
}
Expand All @@ -111,11 +111,11 @@ fn test(
b;
//^ impl Foo
c;
//^ &'_ impl Foo + ?Sized
//^ &impl Foo + ?Sized
d;
//^ S<impl Foo>
ref_any;
//^^^^^^^ &'_ impl ?Sized
//^^^^^^^ &impl ?Sized
empty;
} //^^^^^ impl Sized
"#,
Expand Down Expand Up @@ -192,7 +192,7 @@ fn test(
b;
//^ fn(impl Foo) -> impl Foo
c;
} //^ fn(&'_ impl Foo + ?Sized) -> &'_ impl Foo + ?Sized
} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized
"#,
);
}
Expand Down
8 changes: 4 additions & 4 deletions crates/hir-ty/src/tests/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,9 +1153,9 @@ fn dyn_trait_super_trait_not_in_scope() {
51..55 'self': &'? Self
64..69 '{ 0 }': u32
66..67 '0': u32
176..177 'd': &'? dyn Trait
176..177 'd': &'? (dyn Trait + 'static)
191..207 '{ ...o(); }': ()
197..198 'd': &'? dyn Trait
197..198 'd': &'? (dyn Trait + 'static)
197..204 'd.foo()': u32
"#]],
);
Expand Down Expand Up @@ -2019,10 +2019,10 @@ impl dyn Error + Send {
/// Attempts to downcast the box to a concrete type.
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
let err: Box<dyn Error> = self;
// ^^^^ expected Box<dyn Error>, got Box<dyn Error + Send>
// ^^^^ expected Box<dyn Error + 'static>, got Box<dyn Error + Send + 'static>
// FIXME, type mismatch should not occur
<dyn Error>::downcast(err).map_err(|_| loop {})
//^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error>) -> Result<Box<{unknown}>, Box<dyn Error>>
//^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + 'static>) -> Result<Box<{unknown}>, Box<dyn Error + 'static>>
}
}
"#,
Expand Down
4 changes: 2 additions & 2 deletions crates/hir-ty/src/tests/regression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ fn issue_4053_diesel_where_clauses() {
488..522 '{ ... }': ()
498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
498..508 'self.order': O
498..515 'self.o...into()': dyn QueryFragment<DB>
498..515 'self.o...into()': dyn QueryFragment<DB> + 'static
"#]],
);
}
Expand Down Expand Up @@ -773,7 +773,7 @@ fn issue_4800() {
"#,
expect![[r#"
379..383 'self': &'? mut PeerSet<D>
401..424 '{ ... }': dyn Future<Output = ()>
401..424 '{ ... }': dyn Future<Output = ()> + 'static
411..418 'loop {}': !
416..418 '{}': ()
575..579 'self': &'? mut Self
Expand Down
10 changes: 5 additions & 5 deletions crates/hir-ty/src/tests/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2741,11 +2741,11 @@ impl B for Astruct {}
715..744 '#[rust...1i32])': Box<[i32; 1], Global>
737..743 '[1i32]': [i32; 1]
738..742 '1i32': i32
755..756 'v': Vec<Box<dyn B, Global>, Global>
776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
776..850 '<[_]> ...ct)]))': Vec<Box<dyn B, Global>, Global>
794..849 '#[rust...uct)])': Box<[Box<dyn B, Global>; 1], Global>
816..848 '[#[rus...ruct)]': [Box<dyn B, Global>; 1]
755..756 'v': Vec<Box<dyn B + 'static, Global>, Global>
776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B + 'static, Global>, Global>(Box<[Box<dyn B + 'static, Global>], Global>) -> Vec<Box<dyn B + 'static, Global>, Global>
776..850 '<[_]> ...ct)]))': Vec<Box<dyn B + 'static, Global>, Global>
794..849 '#[rust...uct)])': Box<[Box<dyn B + 'static, Global>; 1], Global>
816..848 '[#[rus...ruct)]': [Box<dyn B + 'static, Global>; 1]
817..847 '#[rust...truct)': Box<Astruct, Global>
839..846 'Astruct': Astruct
"#]],
Expand Down
Loading
Loading