Unnamed repository; edit this file 'description' to name the repository.
Do not error at impls for unsized types that do not include `where Self: Sized` items
Chayim Refael Friedman 11 months ago
parent 6acff6c · commit 6f4a6d4
-rw-r--r--crates/hir-ty/src/dyn_compatibility.rs2
-rw-r--r--crates/hir-ty/src/generics.rs2
-rw-r--r--crates/hir/src/lib.rs34
-rw-r--r--crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs29
4 files changed, 64 insertions, 3 deletions
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index ed8d8dc262..48094945c1 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -122,7 +122,7 @@ pub fn dyn_compatibility_of_trait_query(
res
}
-fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool {
+pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool {
let krate = def.module(db).krate();
let Some(sized) = LangItem::Sized.resolve_trait(db, krate) else {
return false;
diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs
index bb4aaf7889..a3ed39934c 100644
--- a/crates/hir-ty/src/generics.rs
+++ b/crates/hir-ty/src/generics.rs
@@ -229,7 +229,7 @@ impl Generics {
}
/// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
- pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
+ pub fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
Substitution::from_iter(
Interner,
self.iter_id().map(|id| match id {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e8218cf861..969fd3eb48 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -846,7 +846,7 @@ impl Module {
)
}
- let missing: Vec<_> = required_items
+ let mut missing: Vec<_> = required_items
.filter(|(name, id)| {
!impl_assoc_items_scratch.iter().any(|(impl_name, impl_item)| {
discriminant(impl_item) == discriminant(id) && impl_name == name
@@ -854,6 +854,38 @@ impl Module {
})
.map(|(name, item)| (name.clone(), AssocItem::from(*item)))
.collect();
+
+ if !missing.is_empty() {
+ let self_ty = db.impl_self_ty(impl_def.id).substitute(
+ Interner,
+ &hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db),
+ );
+ let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) =
+ self_ty.kind(Interner)
+ {
+ db.normalize_projection(
+ projection.clone(),
+ db.trait_environment(impl_def.id.into()),
+ )
+ } else {
+ self_ty
+ };
+ let self_ty_is_guaranteed_unsized = matches!(
+ self_ty.kind(Interner),
+ TyKind::Dyn(..) | TyKind::Slice(..) | TyKind::Str
+ );
+ if self_ty_is_guaranteed_unsized {
+ missing.retain(|(_, assoc_item)| {
+ let assoc_item = match *assoc_item {
+ AssocItem::Function(it) => it.id.into(),
+ AssocItem::Const(it) => it.id.into(),
+ AssocItem::TypeAlias(it) => it.id.into(),
+ };
+ !hir_ty::dyn_compatibility::generics_require_sized_self(db, assoc_item)
+ });
+ }
+ }
+
if !missing.is_empty() {
acc.push(
TraitImplMissingAssocItems {
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 fa7ba90a75..0e18ce9674 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
@@ -127,4 +127,33 @@ impl !Trait for () {}
"#,
)
}
+
+ #[test]
+ fn impl_sized_for_unsized() {
+ check_diagnostics(
+ r#"
+//- minicore: sized
+trait Trait {
+ type Item
+ where
+ Self: Sized;
+
+ fn item()
+ where
+ Self: Sized;
+}
+
+trait OtherTrait {}
+
+impl Trait for () {
+ 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 {}
+ "#,
+ )
+ }
}