Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir/src/lib.rs53
-rw-r--r--crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs8
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]);
"#,
)
}