Unnamed repository; edit this file 'description' to name the repository.
fix: no lint unsized adt self_ty missing bounded assoc
Example
---
```rust
trait Trait {
fn item() where Self: Sized;
}
impl Trait for Adt {}
struct Adt([i32]);
```
**Before this PR**
```
error: not all trait items implemented, missing: `fn item`
```
**After this PR**
no lint
| -rw-r--r-- | crates/hir/src/lib.rs | 53 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs | 8 |
2 files changed, 55 insertions, 6 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 0423a8fc4f..53df9f21dd 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -946,14 +946,17 @@ impl Module { .collect(); if !missing.is_empty() { + let env = ParamEnvAndCrate { + param_env: db.trait_environment(GenericDefId::from(impl_id).into()), + krate: self.id.krate(db), + }; let self_ty = db.impl_self_ty(impl_id).instantiate_identity().skip_norm_wip(); - let self_ty = structurally_normalize_ty( - &infcx, - self_ty, - db.trait_environment(GenericDefId::from(impl_id).into()), - ); + let self_ty = structurally_normalize_ty(&infcx, self_ty, env.param_env); + let tail_ty = struct_tail_raw(db, interner, self_ty, |ty| { + structurally_normalize_ty(&infcx, ty, env.param_env) + }); let self_ty_is_guaranteed_unsized = matches!( - self_ty.kind(), + tail_ty.kind(), TyKind::Dynamic(..) | TyKind::Slice(..) | TyKind::Str ); if self_ty_is_guaranteed_unsized { @@ -7455,5 +7458,43 @@ fn empty_param_env<'db>(krate: base_db::Crate) -> ParamEnvAndCrate<'db> { ParamEnvAndCrate { param_env: ParamEnv::empty(), krate } } +// Like https://github.com/rust-lang/rust/blob/7c3c88f42ad444f4688b865591d84660be4ece2f/compiler/rustc_middle/src/ty/util.rs#L254-L310 +pub fn struct_tail_raw<'db>( + db: &'db dyn HirDatabase, + interner: DbInterner<'db>, + mut ty: Ty<'db>, + mut normalize: impl FnMut(Ty<'db>) -> Ty<'db>, +) -> Ty<'db> { + let recursion_limit = 16; + for iteration in 0.. { + if iteration >= recursion_limit { + return Ty::new_error(interner, ErrorGuaranteed); + } + match ty.kind() { + TyKind::Adt(def, args) => { + let AdtId::StructId(def_id) = def.def_id() else { break }; + let last_field = db.field_types(def_id.into()).iter().next_back(); + match last_field { + Some((_, field)) => { + ty = normalize(field.get().instantiate(interner, args).skip_norm_wip()) + } + None => break, + } + } + TyKind::Tuple(tys) if let Some((&last_ty, _)) = tys.split_last() => { + ty = last_ty; + } + TyKind::Tuple(_) => break, + TyKind::Pat(inner, _) => { + ty = inner; + } + _ => { + break; + } + } + } + ty +} + pub use hir_ty::next_solver; pub use hir_ty::setup_tracing; diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index 5f5e155bd7..1ffef25b50 100644 --- a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -149,10 +149,18 @@ impl Trait for () { type Item = (); fn item() {} } +impl Trait for Adt<i32> {} + //^^^^^ error: not all trait items implemented, missing: `type Item`, `fn item` // Items with Self: Sized bound not required to be implemented for unsized types. impl Trait for str {} impl Trait for dyn OtherTrait {} +impl Trait for Adt<[i32]> {} +impl Trait for Slice<i32> {} +impl Trait for (str,) {} + +struct Adt<T>(i32, T); +struct Slice<T>([T]); "#, ) } |