Adjust display impls to respect lifetime bounds

This commit is contained in:
Lukas Wirth 2024-04-02 14:05:28 +02:00
parent 0927f86247
commit 707be6b99c
8 changed files with 164 additions and 24 deletions

View File

@ -30,6 +30,8 @@ pub fn find_path(
find_path_inner(FindPathCtx { db, prefixed: None, prefer_no_std, prefer_prelude }, item, from) find_path_inner(FindPathCtx { db, prefixed: None, prefer_no_std, prefer_prelude }, item, from)
} }
/// Find a path that can be used to refer to a certain item. This can depend on
/// *from where* you're referring to the item, hence the `from` parameter.
pub fn find_path_prefixed( pub fn find_path_prefixed(
db: &dyn DefDatabase, db: &dyn DefDatabase,
item: ItemInNs, item: ItemInNs,
@ -255,7 +257,7 @@ fn find_in_scope(
item: ItemInNs, item: ItemInNs,
) -> Option<Name> { ) -> Option<Name> {
def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
def_map[local_id].scope.name_of(item).map(|(name, _, _)| name.clone()) def_map[local_id].scope.names_of(item, |name, _, _| Some(name.clone()))
}) })
} }

View File

@ -29,6 +29,8 @@ use crate::{
/// Data about a generic type parameter (to a function, struct, impl, ...). /// Data about a generic type parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TypeParamData { pub struct TypeParamData {
/// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
/// make it always be a value, giving impl trait a special name.
pub name: Option<Name>, pub name: Option<Name>,
pub default: Option<Interned<TypeRef>>, pub default: Option<Interned<TypeRef>>,
pub provenance: TypeParamProvenance, pub provenance: TypeParamProvenance,

View File

@ -277,13 +277,43 @@ impl ItemScope {
ItemInNs::Types(def) => self.types.iter().find_map(|(name, &(other_def, vis, i))| { ItemInNs::Types(def) => self.types.iter().find_map(|(name, &(other_def, vis, i))| {
(other_def == def).then_some((name, vis, i.is_none())) (other_def == def).then_some((name, vis, i.is_none()))
}), }),
ItemInNs::Values(def) => self.values.iter().find_map(|(name, &(other_def, vis, i))| { ItemInNs::Values(def) => self.values.iter().find_map(|(name, &(other_def, vis, i))| {
(other_def == def).then_some((name, vis, i.is_none())) (other_def == def).then_some((name, vis, i.is_none()))
}), }),
} }
} }
/// XXX: this is O(N) rather than O(1), try to not introduce new usages.
pub(crate) fn names_of<T>(
&self,
item: ItemInNs,
mut cb: impl FnMut(&Name, Visibility, bool) -> Option<T>,
) -> Option<T> {
match item {
ItemInNs::Macros(def) => self
.macros
.iter()
.filter_map(|(name, &(other_def, vis, i))| {
(other_def == def).then_some((name, vis, i.is_none()))
})
.find_map(|(a, b, c)| cb(a, b, c)),
ItemInNs::Types(def) => self
.types
.iter()
.filter_map(|(name, &(other_def, vis, i))| {
(other_def == def).then_some((name, vis, i.is_none()))
})
.find_map(|(a, b, c)| cb(a, b, c)),
ItemInNs::Values(def) => self
.values
.iter()
.filter_map(|(name, &(other_def, vis, i))| {
(other_def == def).then_some((name, vis, i.is_none()))
})
.find_map(|(a, b, c)| cb(a, b, c)),
}
}
pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ { pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
self.types self.types
.values() .values()

View File

@ -9,6 +9,7 @@ use std::{
use base_db::CrateId; use base_db::CrateId;
use chalk_ir::{BoundVar, Safety, TyKind}; use chalk_ir::{BoundVar, Safety, TyKind};
use either::Either;
use hir_def::{ use hir_def::{
data::adt::VariantData, data::adt::VariantData,
db::DefDatabase, db::DefDatabase,
@ -1072,6 +1073,7 @@ impl HirDisplay for Ty {
write_bounds_like_dyn_trait_with_prefix( write_bounds_like_dyn_trait_with_prefix(
f, f,
"impl", "impl",
Either::Left(self),
bounds.skip_binders(), bounds.skip_binders(),
SizedByDefault::Sized { anchor: krate }, SizedByDefault::Sized { anchor: krate },
)?; )?;
@ -1087,6 +1089,7 @@ impl HirDisplay for Ty {
write_bounds_like_dyn_trait_with_prefix( write_bounds_like_dyn_trait_with_prefix(
f, f,
"impl", "impl",
Either::Left(self),
bounds.skip_binders(), bounds.skip_binders(),
SizedByDefault::Sized { anchor: krate }, SizedByDefault::Sized { anchor: krate },
)?; )?;
@ -1189,21 +1192,24 @@ impl HirDisplay for Ty {
.generic_predicates(id.parent) .generic_predicates(id.parent)
.iter() .iter()
.map(|pred| pred.clone().substitute(Interner, &substs)) .map(|pred| pred.clone().substitute(Interner, &substs))
.filter(|wc| match &wc.skip_binders() { .filter(|wc| match wc.skip_binders() {
WhereClause::Implemented(tr) => { WhereClause::Implemented(tr) => {
&tr.self_type_parameter(Interner) == self tr.self_type_parameter(Interner) == *self
} }
WhereClause::AliasEq(AliasEq { WhereClause::AliasEq(AliasEq {
alias: AliasTy::Projection(proj), alias: AliasTy::Projection(proj),
ty: _, ty: _,
}) => &proj.self_type_parameter(db) == self, }) => proj.self_type_parameter(db) == *self,
_ => false, WhereClause::AliasEq(_) => false,
WhereClause::TypeOutlives(to) => to.ty == *self,
WhereClause::LifetimeOutlives(_) => false,
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let krate = id.parent.module(db.upcast()).krate(); let krate = id.parent.module(db.upcast()).krate();
write_bounds_like_dyn_trait_with_prefix( write_bounds_like_dyn_trait_with_prefix(
f, f,
"impl", "impl",
Either::Left(self),
&bounds, &bounds,
SizedByDefault::Sized { anchor: krate }, SizedByDefault::Sized { anchor: krate },
)?; )?;
@ -1229,6 +1235,7 @@ impl HirDisplay for Ty {
write_bounds_like_dyn_trait_with_prefix( write_bounds_like_dyn_trait_with_prefix(
f, f,
"dyn", "dyn",
Either::Left(self),
&bounds, &bounds,
SizedByDefault::NotSized, SizedByDefault::NotSized,
)?; )?;
@ -1252,6 +1259,7 @@ impl HirDisplay for Ty {
write_bounds_like_dyn_trait_with_prefix( write_bounds_like_dyn_trait_with_prefix(
f, f,
"impl", "impl",
Either::Left(self),
bounds.skip_binders(), bounds.skip_binders(),
SizedByDefault::Sized { anchor: krate }, SizedByDefault::Sized { anchor: krate },
)?; )?;
@ -1266,6 +1274,7 @@ impl HirDisplay for Ty {
write_bounds_like_dyn_trait_with_prefix( write_bounds_like_dyn_trait_with_prefix(
f, f,
"impl", "impl",
Either::Left(self),
bounds.skip_binders(), bounds.skip_binders(),
SizedByDefault::Sized { anchor: krate }, SizedByDefault::Sized { anchor: krate },
)?; )?;
@ -1468,6 +1477,7 @@ impl SizedByDefault {
pub fn write_bounds_like_dyn_trait_with_prefix( pub fn write_bounds_like_dyn_trait_with_prefix(
f: &mut HirFormatter<'_>, f: &mut HirFormatter<'_>,
prefix: &str, prefix: &str,
this: Either<&Ty, &Lifetime>,
predicates: &[QuantifiedWhereClause], predicates: &[QuantifiedWhereClause],
default_sized: SizedByDefault, default_sized: SizedByDefault,
) -> Result<(), HirDisplayError> { ) -> Result<(), HirDisplayError> {
@ -1476,7 +1486,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix(
|| predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. }) || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
{ {
write!(f, " ")?; write!(f, " ")?;
write_bounds_like_dyn_trait(f, predicates, default_sized) write_bounds_like_dyn_trait(f, this, predicates, default_sized)
} else { } else {
Ok(()) Ok(())
} }
@ -1484,6 +1494,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix(
fn write_bounds_like_dyn_trait( fn write_bounds_like_dyn_trait(
f: &mut HirFormatter<'_>, f: &mut HirFormatter<'_>,
this: Either<&Ty, &Lifetime>,
predicates: &[QuantifiedWhereClause], predicates: &[QuantifiedWhereClause],
default_sized: SizedByDefault, default_sized: SizedByDefault,
) -> Result<(), HirDisplayError> { ) -> Result<(), HirDisplayError> {
@ -1541,6 +1552,28 @@ fn write_bounds_like_dyn_trait(
} }
} }
} }
WhereClause::TypeOutlives(to) if Either::Left(&to.ty) == this => {
if !is_fn_trait && angle_open {
write!(f, ">")?;
angle_open = false;
}
if !first {
write!(f, " + ")?;
}
to.lifetime.hir_fmt(f)?;
}
WhereClause::TypeOutlives(_) => {}
WhereClause::LifetimeOutlives(lo) if Either::Right(&lo.a) == this => {
if !is_fn_trait && angle_open {
write!(f, ">")?;
angle_open = false;
}
if !first {
write!(f, " + ")?;
}
lo.b.hir_fmt(f)?;
}
WhereClause::LifetimeOutlives(_) => {}
WhereClause::AliasEq(alias_eq) if is_fn_trait => { WhereClause::AliasEq(alias_eq) if is_fn_trait => {
is_fn_trait = false; is_fn_trait = false;
if !alias_eq.ty.is_unit() { if !alias_eq.ty.is_unit() {
@ -1577,10 +1610,6 @@ fn write_bounds_like_dyn_trait(
} }
ty.hir_fmt(f)?; ty.hir_fmt(f)?;
} }
// FIXME implement these
WhereClause::LifetimeOutlives(_) => {}
WhereClause::TypeOutlives(_) => {}
} }
first = false; first = false;
} }

View File

@ -1612,10 +1612,10 @@ fn test(
) {} ) {}
"#, "#,
expect![[r#" expect![[r#"
28..29 'a': impl Trait 28..29 'a': impl Trait + 'static
59..60 'b': impl Sized 59..60 'b': impl 'static
82..83 'c': impl Trait 82..83 'c': impl Trait
103..104 'd': impl Sized 103..104 'd': impl 'static
128..129 'e': impl ?Sized 128..129 'e': impl ?Sized
148..149 'f': impl Trait + ?Sized 148..149 'f': impl Trait + ?Sized
173..175 '{}': () 173..175 '{}': ()

View File

@ -1,4 +1,5 @@
//! HirDisplay implementations for various hir types. //! HirDisplay implementations for various hir types.
use either::Either;
use hir_def::{ use hir_def::{
data::adt::{StructKind, VariantData}, data::adt::{StructKind, VariantData},
generics::{ generics::{
@ -13,7 +14,7 @@ use hir_ty::{
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
HirFormatter, SizedByDefault, HirFormatter, SizedByDefault,
}, },
Interner, TraitRefExt, WhereClause, AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
}; };
use crate::{ use crate::{
@ -363,16 +364,52 @@ impl HirDisplay for TypeOrConstParam {
impl HirDisplay for TypeParam { impl HirDisplay for TypeParam {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let params = f.db.generic_params(self.id.parent());
let param_data = &params.type_or_consts[self.id.local_id()];
let substs = TyBuilder::placeholder_subst(f.db, self.id.parent());
let krate = self.id.parent().krate(f.db).id;
let ty =
TyKind::Placeholder(hir_ty::to_placeholder_idx(f.db, self.id.into())).intern(Interner);
let predicates = f.db.generic_predicates(self.id.parent());
let predicates = predicates
.iter()
.cloned()
.map(|pred| pred.substitute(Interner, &substs))
.filter(|wc| match wc.skip_binders() {
WhereClause::Implemented(tr) => tr.self_type_parameter(Interner) == ty,
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), ty: _ }) => {
proj.self_type_parameter(f.db) == ty
}
WhereClause::AliasEq(_) => false,
WhereClause::TypeOutlives(to) => to.ty == ty,
WhereClause::LifetimeOutlives(_) => false,
})
.collect::<Vec<_>>();
match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
write!(f, "{}", p.name.clone().unwrap().display(f.db.upcast()))?
}
TypeParamProvenance::ArgumentImplTrait => {
return write_bounds_like_dyn_trait_with_prefix(
f,
"impl",
Either::Left(&ty),
&predicates,
SizedByDefault::Sized { anchor: krate },
);
}
},
TypeOrConstParamData::ConstParamData(p) => {
write!(f, "{}", p.name.display(f.db.upcast()))?;
}
}
if f.omit_verbose_types() { if f.omit_verbose_types() {
return Ok(()); return Ok(());
} }
let bounds = f.db.generic_predicates_for_param(self.id.parent(), self.id.into(), None);
let substs = TyBuilder::placeholder_subst(f.db, self.id.parent());
let predicates: Vec<_> =
bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect();
let krate = self.id.parent().krate(f.db).id;
let sized_trait = let sized_trait =
f.db.lang_item(krate, LangItem::Sized).and_then(|lang_item| lang_item.as_trait()); f.db.lang_item(krate, LangItem::Sized).and_then(|lang_item| lang_item.as_trait());
let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() { let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
@ -382,7 +419,16 @@ impl HirDisplay for TypeParam {
let has_only_not_sized_bound = predicates.is_empty(); let has_only_not_sized_bound = predicates.is_empty();
if !has_only_sized_bound || has_only_not_sized_bound { if !has_only_sized_bound || has_only_not_sized_bound {
let default_sized = SizedByDefault::Sized { anchor: krate }; let default_sized = SizedByDefault::Sized { anchor: krate };
write_bounds_like_dyn_trait_with_prefix(f, ":", &predicates, default_sized)?; write_bounds_like_dyn_trait_with_prefix(
f,
":",
Either::Left(
&hir_ty::TyKind::Placeholder(hir_ty::to_placeholder_idx(f.db, self.id.into()))
.intern(Interner),
),
&predicates,
default_sized,
)?;
} }
Ok(()) Ok(())
} }

View File

@ -1585,6 +1585,38 @@ mod bar {
Foo; Foo;
} }
} }
"#,
);
}
#[test]
fn local_inline_import_has_alias() {
// FIXME
check_assist_not_applicable(
auto_import,
r#"
struct S<T>(T);
use S as IoResult;
mod foo {
pub fn bar() -> S$0<()> {}
}
"#,
);
}
#[test]
fn alias_local() {
// FIXME
check_assist_not_applicable(
auto_import,
r#"
struct S<T>(T);
use S as IoResult;
mod foo {
pub fn bar() -> IoResult$0<()> {}
}
"#, "#,
); );
} }

View File

@ -4040,7 +4040,6 @@ impl<T> Foo<T$0> {}
``` ```
"#]], "#]],
); );
// lifetimes bounds arent being tracked yet
check( check(
r#" r#"
//- minicore: sized //- minicore: sized
@ -4051,7 +4050,7 @@ impl<T: 'static> Foo<T$0> {}
*T* *T*
```rust ```rust
T T: 'static
``` ```
"#]], "#]],
); );