diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 0cd4a5db8c3..d06fc4df768 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -30,6 +30,8 @@ pub fn find_path( 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( db: &dyn DefDatabase, item: ItemInNs, @@ -255,7 +257,7 @@ fn find_in_scope( item: ItemInNs, ) -> Option { 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())) }) } diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index 4638b377197..118055b605e 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -29,6 +29,8 @@ use crate::{ /// Data about a generic type parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug, Hash)] 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, pub default: Option>, pub provenance: TypeParamProvenance, diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 2b059d1f8dc..a60b9f9f3ab 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -277,13 +277,43 @@ impl ItemScope { ItemInNs::Types(def) => self.types.iter().find_map(|(name, &(other_def, vis, i))| { (other_def == def).then_some((name, vis, i.is_none())) }), - ItemInNs::Values(def) => self.values.iter().find_map(|(name, &(other_def, vis, i))| { (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( + &self, + item: ItemInNs, + mut cb: impl FnMut(&Name, Visibility, bool) -> Option, + ) -> Option { + 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 + '_ { self.types .values() diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 8740ae6797c..eb7f106cdfa 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -9,6 +9,7 @@ use std::{ use base_db::CrateId; use chalk_ir::{BoundVar, Safety, TyKind}; +use either::Either; use hir_def::{ data::adt::VariantData, db::DefDatabase, @@ -1072,6 +1073,7 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "impl", + Either::Left(self), bounds.skip_binders(), SizedByDefault::Sized { anchor: krate }, )?; @@ -1087,6 +1089,7 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "impl", + Either::Left(self), bounds.skip_binders(), SizedByDefault::Sized { anchor: krate }, )?; @@ -1189,21 +1192,24 @@ impl HirDisplay for Ty { .generic_predicates(id.parent) .iter() .map(|pred| pred.clone().substitute(Interner, &substs)) - .filter(|wc| match &wc.skip_binders() { + .filter(|wc| match wc.skip_binders() { WhereClause::Implemented(tr) => { - &tr.self_type_parameter(Interner) == self + tr.self_type_parameter(Interner) == *self } WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), ty: _, - }) => &proj.self_type_parameter(db) == self, - _ => false, + }) => proj.self_type_parameter(db) == *self, + WhereClause::AliasEq(_) => false, + WhereClause::TypeOutlives(to) => to.ty == *self, + WhereClause::LifetimeOutlives(_) => false, }) .collect::>(); let krate = id.parent.module(db.upcast()).krate(); write_bounds_like_dyn_trait_with_prefix( f, "impl", + Either::Left(self), &bounds, SizedByDefault::Sized { anchor: krate }, )?; @@ -1229,6 +1235,7 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "dyn", + Either::Left(self), &bounds, SizedByDefault::NotSized, )?; @@ -1252,6 +1259,7 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "impl", + Either::Left(self), bounds.skip_binders(), SizedByDefault::Sized { anchor: krate }, )?; @@ -1266,6 +1274,7 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "impl", + Either::Left(self), bounds.skip_binders(), SizedByDefault::Sized { anchor: krate }, )?; @@ -1468,6 +1477,7 @@ impl SizedByDefault { pub fn write_bounds_like_dyn_trait_with_prefix( f: &mut HirFormatter<'_>, prefix: &str, + this: Either<&Ty, &Lifetime>, predicates: &[QuantifiedWhereClause], default_sized: SizedByDefault, ) -> Result<(), HirDisplayError> { @@ -1476,7 +1486,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix( || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. }) { write!(f, " ")?; - write_bounds_like_dyn_trait(f, predicates, default_sized) + write_bounds_like_dyn_trait(f, this, predicates, default_sized) } else { Ok(()) } @@ -1484,6 +1494,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix( fn write_bounds_like_dyn_trait( f: &mut HirFormatter<'_>, + this: Either<&Ty, &Lifetime>, predicates: &[QuantifiedWhereClause], default_sized: SizedByDefault, ) -> 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 => { is_fn_trait = false; if !alias_eq.ty.is_unit() { @@ -1577,10 +1610,6 @@ fn write_bounds_like_dyn_trait( } ty.hir_fmt(f)?; } - - // FIXME implement these - WhereClause::LifetimeOutlives(_) => {} - WhereClause::TypeOutlives(_) => {} } first = false; } diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 759af18c98b..fac850eeaf3 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -1612,10 +1612,10 @@ fn test( ) {} "#, expect![[r#" - 28..29 'a': impl Trait - 59..60 'b': impl Sized + 28..29 'a': impl Trait + 'static + 59..60 'b': impl 'static 82..83 'c': impl Trait - 103..104 'd': impl Sized + 103..104 'd': impl 'static 128..129 'e': impl ?Sized 148..149 'f': impl Trait + ?Sized 173..175 '{}': () diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 23c6b078b96..84f03d111f2 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -1,4 +1,5 @@ //! HirDisplay implementations for various hir types. +use either::Either; use hir_def::{ data::adt::{StructKind, VariantData}, generics::{ @@ -13,7 +14,7 @@ use hir_ty::{ write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, HirFormatter, SizedByDefault, }, - Interner, TraitRefExt, WhereClause, + AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause, }; use crate::{ @@ -363,16 +364,52 @@ impl HirDisplay for TypeOrConstParam { impl HirDisplay for TypeParam { 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 = ¶ms.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::>(); + + 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() { 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 = 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() { @@ -382,7 +419,16 @@ impl HirDisplay for TypeParam { let has_only_not_sized_bound = predicates.is_empty(); if !has_only_sized_bound || has_only_not_sized_bound { 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(()) } diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index 62696d1a9a8..5545e41f530 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -1585,6 +1585,38 @@ mod bar { Foo; } } +"#, + ); + } + + #[test] + fn local_inline_import_has_alias() { + // FIXME + check_assist_not_applicable( + auto_import, + r#" +struct S(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); +use S as IoResult; + +mod foo { + pub fn bar() -> IoResult$0<()> {} +} "#, ); } diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 08925fcdff5..d1721f1191a 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -4040,7 +4040,6 @@ impl Foo {} ``` "#]], ); - // lifetimes bounds arent being tracked yet check( r#" //- minicore: sized @@ -4051,7 +4050,7 @@ impl Foo {} *T* ```rust - T + T: 'static ``` "#]], );