Merge #10202
10202: fix: Type param hover shows correct sized bounds. r=flodiebold a=iDawer Closes #9949 This adds implicit `: Sized` bound to type parameters at lowering step. Hovering on type parameter does not show it's `: Sized` bound be it set explicitly or implicitly. This is because it doesn't track that the bound was set implicitly. ### Perf ```rust ./target/rust-analyzer-baseline-3dae94bf -q analysis-stats --memory-usage . Database loaded: 4.51s, 311minstr, 110mb (metadata 1.08s, 22minstr, 743kb; build 3.20s, 8730kinstr, -237kb) crates: 38, mods: 770, decls: 17173, fns: 12835 Item Collection: 29.63s, 85ginstr, 372mb exprs: 353460, ??ty: 364 (0%), ?ty: 232 (0%), !ty: 144 Inference: 118.25s, 284ginstr, 601mb Total: 147.88s, 370ginstr, 973mb ./target/rust-analyzer-hover-ty-param-dfb15292 -q analysis-stats --memory-usage . Database loaded: 4.53s, 311minstr, 110mb (metadata 1.10s, 22minstr, 743kb; build 3.20s, 8672kinstr, -189kb) crates: 38, mods: 770, decls: 17173, fns: 12835 Item Collection: 29.59s, 85ginstr, 372mb exprs: 353460, ??ty: 364 (0%), ?ty: 232 (0%), !ty: 144 Inference: 121.69s, 296ginstr, 601mb Total: 151.28s, 382ginstr, 974mb ``` Co-authored-by: Dawer <7803845+iDawer@users.noreply.github.com>
This commit is contained in:
commit
317059985a
@ -5,16 +5,19 @@
|
||||
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 {
|
||||
@ -234,12 +237,24 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
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(())
|
||||
|
@ -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 {
|
||||
@ -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(
|
||||
|
@ -3564,20 +3564,21 @@ fn hover_type_param() {
|
||||
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> {}
|
||||
"#,
|
||||
@ -3592,6 +3593,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> {}
|
||||
"#,
|
||||
@ -3606,23 +3608,178 @@ 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: Copy + Clone + ?Sized
|
||||
T: Trait
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait {}
|
||||
struct Foo<T>(T);
|
||||
impl<T: Trait + ?Sized> Foo<T$0> {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*T*
|
||||
|
||||
```rust
|
||||
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]
|
||||
|
Loading…
Reference in New Issue
Block a user