about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-01-09 00:22:35 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-01-19 23:37:39 +0000
commit6b7e6ea590ad0179e9c61c5e007220ae1e4b9644 (patch)
tree1ba3bb5ad676da849d6ee2b62034251f41c0b54a
parentb1688b48d2841a1421cb7ed0afd32ce0c3eeb20a (diff)
downloadrust-6b7e6ea590ad0179e9c61c5e007220ae1e4b9644.tar.gz
rust-6b7e6ea590ad0179e9c61c5e007220ae1e4b9644.zip
Account for traits using self-trait by name without `dyn`
Fix #119652.
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs24
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs19
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr105
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs17
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr65
5 files changed, 222 insertions, 8 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index bf668f311cc..b5f42e98127 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -78,14 +78,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool {
         let tcx = self.tcx();
         let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
-        let (hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. })
-        | hir::Node::TraitItem(hir::TraitItem {
-            kind: hir::TraitItemKind::Fn(sig, _),
-            generics,
-            ..
-        })) = tcx.hir_node_by_def_id(parent_id)
-        else {
-            return false;
+        let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
+                (sig, generics, None)
+            }
+            hir::Node::TraitItem(hir::TraitItem {
+                kind: hir::TraitItemKind::Fn(sig, _),
+                generics,
+                owner_id,
+                ..
+            }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
+            _ => return false,
         };
         let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
             return false;
@@ -94,6 +97,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let is_object_safe = match self_ty.kind {
             hir::TyKind::TraitObject(objects, ..) => {
                 objects.iter().all(|o| match o.trait_ref.path.res {
+                    Res::Def(DefKind::Trait, id) if Some(id) == owner => {
+                        // When we're dealing with a recursive trait, we don't want to downgrade
+                        // the error, so we consider them to be object safe always. (#119652)
+                        true
+                    }
                     Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
                     _ => false,
                 })
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
new file mode 100644
index 00000000000..6382480b7e3
--- /dev/null
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
@@ -0,0 +1,19 @@
+// edition:2021
+#![allow(bare_trait_objects)]
+trait A: Sized {
+    fn f(a: A) -> A;
+    //~^ ERROR trait objects must include the `dyn` keyword
+    //~| ERROR trait objects must include the `dyn` keyword
+}
+trait B {
+    fn f(a: B) -> B;
+    //~^ ERROR trait objects must include the `dyn` keyword
+    //~| ERROR trait objects must include the `dyn` keyword
+}
+trait C {
+    fn f(&self, a: C) -> C;
+    //~^ ERROR trait objects must include the `dyn` keyword
+    //~| ERROR trait objects must include the `dyn` keyword
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
new file mode 100644
index 00000000000..1d8ed548046
--- /dev/null
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
@@ -0,0 +1,105 @@
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
+   |
+LL |     fn f(a: A) -> A;
+   |             ^
+   |
+help: use a new generic type parameter, constrained by `A`
+   |
+LL |     fn f<T: A>(a: T) -> A;
+   |         ++++++    ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn f(a: impl A) -> A;
+   |             ++++
+help: alternatively, use a trait object to accept any type that implements `A`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn f(a: &dyn A) -> A;
+   |             ++++
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19
+   |
+LL |     fn f(a: A) -> A;
+   |                   ^
+   |
+help: use `impl A` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn f(a: A) -> impl A;
+   |                   ++++
+help: alternatively, you can return an owned trait object
+   |
+LL |     fn f(a: A) -> Box<dyn A>;
+   |                   +++++++  +
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:9:13
+   |
+LL |     fn f(a: B) -> B;
+   |             ^
+   |
+help: use a new generic type parameter, constrained by `B`
+   |
+LL |     fn f<T: B>(a: T) -> B;
+   |         ++++++    ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn f(a: impl B) -> B;
+   |             ++++
+help: alternatively, use a trait object to accept any type that implements `B`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn f(a: &dyn B) -> B;
+   |             ++++
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:9:19
+   |
+LL |     fn f(a: B) -> B;
+   |                   ^
+   |
+help: use `impl B` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn f(a: B) -> impl B;
+   |                   ++++
+help: alternatively, you can return an owned trait object
+   |
+LL |     fn f(a: B) -> Box<dyn B>;
+   |                   +++++++  +
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:14:20
+   |
+LL |     fn f(&self, a: C) -> C;
+   |                    ^
+   |
+help: use a new generic type parameter, constrained by `C`
+   |
+LL |     fn f<T: C>(&self, a: T) -> C;
+   |         ++++++           ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn f(&self, a: impl C) -> C;
+   |                    ++++
+help: alternatively, use a trait object to accept any type that implements `C`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn f(&self, a: &dyn C) -> C;
+   |                    ++++
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:14:26
+   |
+LL |     fn f(&self, a: C) -> C;
+   |                          ^
+   |
+help: use `impl C` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn f(&self, a: C) -> impl C;
+   |                          ++++
+help: alternatively, you can return an owned trait object
+   |
+LL |     fn f(&self, a: C) -> Box<dyn C>;
+   |                          +++++++  +
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0782`.
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs
new file mode 100644
index 00000000000..a598e883f3f
--- /dev/null
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs
@@ -0,0 +1,17 @@
+// edition:2021
+#![allow(bare_trait_objects)]
+trait A: Sized {
+    fn f(a: dyn A) -> dyn A;
+    //~^ ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `A` cannot be made into an object
+}
+trait B {
+    fn f(a: dyn B) -> dyn B;
+    //~^ ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `B` cannot be made into an object
+}
+trait C {
+    fn f(&self, a: dyn C) -> dyn C;
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr
new file mode 100644
index 00000000000..d6376be9c04
--- /dev/null
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr
@@ -0,0 +1,65 @@
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13
+   |
+LL | trait A: Sized {
+   |       - in this trait
+LL |     fn f(a: dyn A) -> dyn A;
+   |             ^^^^^     ^^^^^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn f(a: Self) -> Self;
+   |             ~~~~     ~~~~
+
+error[E0038]: the trait `A` cannot be made into an object
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13
+   |
+LL |     fn f(a: dyn A) -> dyn A;
+   |             ^^^^^ `A` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:3:10
+   |
+LL | trait A: Sized {
+   |       -  ^^^^^ ...because it requires `Self: Sized`
+   |       |
+   |       this trait cannot be made into an object...
+
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13
+   |
+LL | trait B {
+   |       - in this trait
+LL |     fn f(a: dyn B) -> dyn B;
+   |             ^^^^^     ^^^^^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn f(a: Self) -> Self;
+   |             ~~~~     ~~~~
+
+error[E0038]: the trait `B` cannot be made into an object
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13
+   |
+LL |     fn f(a: dyn B) -> dyn B;
+   |             ^^^^^ `B` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:8
+   |
+LL | trait B {
+   |       - this trait cannot be made into an object...
+LL |     fn f(a: dyn B) -> dyn B;
+   |        ^ ...because associated function `f` has no `self` parameter
+help: consider turning `f` into a method by giving it a `&self` argument
+   |
+LL |     fn f(&self, a: dyn B) -> dyn B;
+   |          ++++++
+help: alternatively, consider constraining `f` so it does not apply to trait objects
+   |
+LL |     fn f(a: dyn B) -> dyn B where Self: Sized;
+   |                             +++++++++++++++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0038`.