diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index f17f19bb77c..d22c4fe201d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -605,7 +605,7 @@ pub(crate) fn complain_about_missing_associated_types( let violations = object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); if !violations.is_empty() { - report_object_safety_error(tcx, *span, trait_def_id, &violations).emit(); + report_object_safety_error(tcx, *span, None, trait_def_id, &violations).emit(); object_safety_violations = true; } } diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index d26f3d5ee91..6675f517cfa 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -122,6 +122,9 @@ fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> ], Applicability::MachineApplicable, ); + } else { + // We'll emit the object safety error already, with a structured suggestion. + diag.downgrade_to_delayed_bug(); } return true; } @@ -145,6 +148,8 @@ fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> } if !is_object_safe { diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`")); + // We'll emit the object safety error already, with a structured suggestion. + diag.downgrade_to_delayed_bug(); } else { let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind { // There are more than one trait bound, we need surrounding parentheses. diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index a614d4abf25..8a3df79cb25 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -140,6 +140,7 @@ trait here instead: `trait NewTrait: {} {{}}`", let reported = report_object_safety_error( tcx, span, + Some(hir_id), item.trait_ref().def_id(), &object_safety_violations, ) diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index d89c205da3f..4aabe5c2922 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -2,9 +2,10 @@ use crate::infer::InferCtxt; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_err, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::Map; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; @@ -42,6 +43,7 @@ pub fn report_extra_impl_obligation( pub fn report_object_safety_error<'tcx>( tcx: TyCtxt<'tcx>, span: Span, + hir_id: Option, trait_def_id: DefId, violations: &[ObjectSafetyViolation], ) -> DiagnosticBuilder<'tcx> { @@ -59,6 +61,24 @@ pub fn report_object_safety_error<'tcx>( ); err.span_label(span, format!("`{trait_str}` cannot be made into an object")); + if let Some(hir_id) = hir_id + && let Some(hir::Node::Ty(ty)) = tcx.hir().find(hir_id) + && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind + { + let mut hir_id = hir_id; + while let hir::Node::Ty(ty) = tcx.hir().get_parent(hir_id) { + hir_id = ty.hir_id; + } + if tcx.hir().get_parent(hir_id).fn_sig().is_some() { + // Do not suggest `impl Trait` when dealing with things like super-traits. + err.span_suggestion_verbose( + ty.span.until(trait_ref.span), + "consider using an opaque type instead", + "impl ", + Applicability::MaybeIncorrect, + ); + } + } let mut reported_violations = FxIndexSet::default(); let mut multi_span = vec![]; let mut messages = vec![]; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index d2598b0defe..81e02a0b17e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -816,7 +816,7 @@ fn report_selection_error( ty::PredicateKind::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); - report_object_safety_error(self.tcx, span, trait_def_id, violations) + report_object_safety_error(self.tcx, span, None, trait_def_id, violations) } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { @@ -924,7 +924,7 @@ fn report_selection_error( TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); - report_object_safety_error(self.tcx, span, did, violations) + report_object_safety_error(self.tcx, span, None, did, violations) } SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => { diff --git a/tests/rustdoc-ui/issues/issue-105742.stderr b/tests/rustdoc-ui/issues/issue-105742.stderr index ad1020a1f08..d5a9031075f 100644 --- a/tests/rustdoc-ui/issues/issue-105742.stderr +++ b/tests/rustdoc-ui/issues/issue-105742.stderr @@ -323,6 +323,10 @@ LL | || Output = ::Item> as SVec>::Item, LL | | LL | | > { | |__^ ...because it uses `Self` as a type parameter +help: consider using an opaque type instead + | +LL | pub fn next<'a, T>(s: &'a mut impl SVec) { + | ~~~~ error[E0107]: missing generics for associated type `SVec::Item` --> $DIR/issue-105742.rs:15:21 diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed index 9720a781eb8..e95b982966d 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed @@ -1,9 +1,7 @@ // run-rustfix #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> impl Ord { - //~^ ERROR trait objects without an explicit `dyn` are deprecated - //~| ERROR the trait `Ord` cannot be made into an object - //~| WARNING this is accepted in the current edition (Rust 2015) + //~^ ERROR the trait `Ord` cannot be made into an object (s.starts_with("."), s) } fn main() { diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs index 31d6e336ccf..fdf7e0a77aa 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs @@ -1,9 +1,7 @@ // run-rustfix #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> Ord { - //~^ ERROR trait objects without an explicit `dyn` are deprecated - //~| ERROR the trait `Ord` cannot be made into an object - //~| WARNING this is accepted in the current edition (Rust 2015) + //~^ ERROR the trait `Ord` cannot be made into an object (s.starts_with("."), s) } fn main() { diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr index 468a570a0f9..2c499d240ab 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr @@ -1,21 +1,3 @@ -error: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-dont-suggest-dyn.rs:3:33 - | -LL | fn ord_prefer_dot(s: String) -> Ord { - | ^^^ - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see -note: the lint level is defined here - --> $DIR/bare-trait-dont-suggest-dyn.rs:2:9 - | -LL | #![deny(bare_trait_objects)] - | ^^^^^^^^^^^^^^^^^^ -help: `Ord` is not object safe, use `impl Ord` to return an opaque type, as long as you return a single underlying type - | -LL | fn ord_prefer_dot(s: String) -> impl Ord { - | ++++ - error[E0038]: the trait `Ord` cannot be made into an object --> $DIR/bare-trait-dont-suggest-dyn.rs:3:33 | @@ -29,7 +11,11 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter +help: consider using an opaque type instead + | +LL | fn ord_prefer_dot(s: String) -> impl Ord { + | ++++ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr index 08df069275a..fc476691d01 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr +++ b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr @@ -11,6 +11,10 @@ LL | trait Baz : Bar { | --- ^^^^^^^^^ ...because it uses `Self` as a type parameter | | | this trait cannot be made into an object... +help: consider using an opaque type instead + | +LL | fn make_baz(t: &T) -> &impl Baz { + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr index 9fe50864642..3b45a510341 100644 --- a/tests/ui/traits/issue-28576.stderr +++ b/tests/ui/traits/issue-28576.stderr @@ -14,6 +14,10 @@ LL | pub trait Bar: Foo { | | | ...because it uses `Self` as a type parameter | | ...because it uses `Self` as a type parameter | this trait cannot be made into an object... +help: consider using an opaque type instead + | +LL | impl Bar + | ~~~~ error: aborting due to 1 previous error