Skip to content
Merged
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
35 changes: 25 additions & 10 deletions crates/hir/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ use hir_def::{
type_ref::{TypeBound, TypeRef},
AdtId, GenericDefId,
};
use hir_ty::display::{
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
HirFormatter, SizedByDefault,
use hir_ty::{
display::{
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
HirFormatter, SizedByDefault,
},
Interner, TraitRefExt, WhereClause,
};
use hir_ty::Interner;
use syntax::ast::{self, NameOwner};

use crate::{
Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasVisibility, LifetimeParam,
Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeParam, Union, Variant,
Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
LifetimeParam, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeParam, Union,
Variant,
};

impl HirDisplay for Function {
Expand Down Expand Up @@ -234,12 +237,24 @@ impl HirDisplay for GenericParam {
impl HirDisplay for TypeParam {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
write!(f, "{}", self.name(f.db))?;
if f.omit_verbose_types() {
return Ok(());
}

let bounds = f.db.generic_predicates_for_param(self.id);
let substs = TyBuilder::type_params_subst(f.db, self.id.parent);
let predicates =
bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect::<Vec<_>>();
if !(predicates.is_empty() || f.omit_verbose_types()) {
let default_sized = SizedByDefault::Sized { anchor: self.module(f.db).krate().id };
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, "sized".into()).and_then(|lang_item| lang_item.as_trait());
let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait,
_ => false,
});
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(":", &predicates, default_sized, f)?;
}
Ok(())
Expand Down
12 changes: 10 additions & 2 deletions crates/hir_ty/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,7 @@ pub(crate) fn generic_predicates_for_param_query(
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
let generics = generics(db.upcast(), param_id.parent);
resolver
let mut predicates: Vec<_> = resolver
.where_predicates_in_scope()
// we have to filter out all other predicates *first*, before attempting to lower them
.filter(|pred| match pred {
Expand All @@ -1038,7 +1038,15 @@ pub(crate) fn generic_predicates_for_param_query(
WherePredicate::Lifetime { .. } => false,
})
.flat_map(|pred| ctx.lower_where_predicate(pred, true).map(|p| make_binders(&generics, p)))
.collect()
.collect();

let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
let implicitly_sized_predicates =
implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
.map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
predicates.extend(implicitly_sized_predicates);
predicates.into()
}

pub(crate) fn generic_predicates_for_param_recover(
Expand Down
175 changes: 166 additions & 9 deletions crates/ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3520,20 +3520,21 @@ fn foo() {
r#"
//- minicore: sized
struct Foo<T>(T);
trait Copy {}
trait Clone {}
impl<T: Copy + Clone> Foo<T$0> where T: Sized {}
trait TraitA {}
trait TraitB {}
impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {}
"#,
expect![[r#"
*T*

```rust
T: Copy + Clone
T: TraitA + TraitB
```
"#]],
);
check(
r#"
//- minicore: sized
struct Foo<T>(T);
impl<T> Foo<T$0> {}
"#,
Expand All @@ -3548,6 +3549,7 @@ impl<T> Foo<T$0> {}
// lifetimes bounds arent being tracked yet
check(
r#"
//- minicore: sized
struct Foo<T>(T);
impl<T: 'static> Foo<T$0> {}
"#,
Expand All @@ -3562,25 +3564,180 @@ impl<T: 'static> Foo<T$0> {}
}

#[test]
fn hover_type_param_not_sized() {
fn hover_type_param_sized_bounds() {
// implicit `: Sized` bound
check(
r#"
//- minicore: sized
trait Trait {}
struct Foo<T>(T);
trait Copy {}
trait Clone {}
impl<T: Copy + Clone> Foo<T$0> where T: ?Sized {}
impl<T: Trait> Foo<T$0> {}
"#,
expect![[r#"
*T*

```rust
T: Trait
```
"#]],
);
check(
r#"
//- minicore: sized
trait Trait {}
struct Foo<T>(T);
impl<T: Trait + ?Sized> Foo<T$0> {}
"#,
expect![[r#"
*T*

```rust
T: Copy + Clone + ?Sized
T: Trait + ?Sized
```
"#]],
);
}

mod type_param_sized_bounds {
use super::*;

#[test]
fn single_implicit() {
check(
r#"
//- minicore: sized
fn foo<T$0>() {}
"#,
expect![[r#"
*T*

```rust
T
```
"#]],
);
}

#[test]
fn single_explicit() {
check(
r#"
//- minicore: sized
fn foo<T$0: Sized>() {}
"#,
expect![[r#"
*T*

```rust
T
```
"#]],
);
}

#[test]
fn single_relaxed() {
check(
r#"
//- minicore: sized
fn foo<T$0: ?Sized>() {}
"#,
expect![[r#"
*T*

```rust
T: ?Sized
```
"#]],
);
}

#[test]
fn multiple_implicit() {
check(
r#"
//- minicore: sized
trait Trait {}
fn foo<T$0: Trait>() {}
"#,
expect![[r#"
*T*

```rust
T: Trait
```
"#]],
);
}

#[test]
fn multiple_explicit() {
check(
r#"
//- minicore: sized
trait Trait {}
fn foo<T$0: Trait + Sized>() {}
"#,
expect![[r#"
*T*

```rust
T: Trait
```
"#]],
);
}

#[test]
fn multiple_relaxed() {
check(
r#"
//- minicore: sized
trait Trait {}
fn foo<T$0: Trait + ?Sized>() {}
"#,
expect![[r#"
*T*

```rust
T: Trait + ?Sized
```
"#]],
);
}

#[test]
fn mixed() {
check(
r#"
//- minicore: sized
fn foo<T$0: ?Sized + Sized + Sized>() {}
"#,
expect![[r#"
*T*

```rust
T
```
"#]],
);
check(
r#"
//- minicore: sized
trait Trait {}
fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
"#,
expect![[r#"
*T*

```rust
T: Trait
```
"#]],
);
}
}

#[test]
fn hover_const_param() {
check(
Expand Down