1pub mod ambiguity;
2pub mod call_kind;
3pub mod fulfillment_errors;
4pub mod on_unimplemented;
5pub mod on_unimplemented_condition;
6pub mod on_unimplemented_format;
7mod overflow;
8pub mod suggestions;
9
10use std::{fmt, iter};
11
12use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
13use rustc_data_structures::unord::UnordSet;
14use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
15use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
16use rustc_hir::intravisit::Visitor;
17use rustc_hir::{self as hir, AmbigArg};
18use rustc_infer::traits::solve::Goal;
19use rustc_infer::traits::{
20 DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
21 PredicateObligation, SelectionError,
22};
23use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
24use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
25use rustc_session::cstore::{ExternCrate, ExternCrateSource};
26use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span};
27use tracing::{info, instrument};
28
29pub use self::overflow::*;
30use crate::error_reporting::TypeErrCtxt;
31use crate::traits::{FulfillmentError, FulfillmentErrorCode};
32
33#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
38pub enum CandidateSimilarity {
39 Exact { ignoring_lifetimes: bool },
40 Fuzzy { ignoring_lifetimes: bool },
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub struct ImplCandidate<'tcx> {
45 pub trait_ref: ty::TraitRef<'tcx>,
46 pub similarity: CandidateSimilarity,
47 impl_def_id: DefId,
48}
49
50enum GetSafeTransmuteErrorAndReason {
51 Silent,
52 Default,
53 Error { err_msg: String, safe_transmute_explanation: Option<String> },
54}
55
56pub struct FindExprBySpan<'hir> {
58 pub span: Span,
59 pub result: Option<&'hir hir::Expr<'hir>>,
60 pub ty_result: Option<&'hir hir::Ty<'hir>>,
61 pub include_closures: bool,
62 pub tcx: TyCtxt<'hir>,
63}
64
65impl<'hir> FindExprBySpan<'hir> {
66 pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
67 Self { span, result: None, ty_result: None, tcx, include_closures: false }
68 }
69}
70
71impl<'v> Visitor<'v> for FindExprBySpan<'v> {
72 type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
73
74 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
75 self.tcx
76 }
77
78 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
79 if self.span == ex.span {
80 self.result = Some(ex);
81 } else {
82 if let hir::ExprKind::Closure(..) = ex.kind
83 && self.include_closures
84 && let closure_header_sp = self.span.with_hi(ex.span.hi())
85 && closure_header_sp == ex.span
86 {
87 self.result = Some(ex);
88 }
89 hir::intravisit::walk_expr(self, ex);
90 }
91 }
92
93 fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
94 if self.span == ty.span {
95 self.ty_result = Some(ty.as_unambig_ty());
96 } else {
97 hir::intravisit::walk_ty(self, ty);
98 }
99 }
100}
101
102#[derive(Clone)]
104pub enum ArgKind {
105 Arg(String, String),
107
108 Tuple(Option<Span>, Vec<(String, String)>),
113}
114
115impl ArgKind {
116 fn empty() -> ArgKind {
117 ArgKind::Arg("_".to_owned(), "_".to_owned())
118 }
119
120 pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
123 match t.kind() {
124 ty::Tuple(tys) => ArgKind::Tuple(
125 span,
126 tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
127 ),
128 _ => ArgKind::Arg("_".to_owned(), t.to_string()),
129 }
130 }
131}
132
133#[derive(Copy, Clone)]
134pub enum DefIdOrName {
135 DefId(DefId),
136 Name(&'static str),
137}
138
139impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
140 pub fn report_fulfillment_errors(
141 &self,
142 mut errors: Vec<FulfillmentError<'tcx>>,
143 ) -> ErrorGuaranteed {
144 #[derive(Debug)]
145 struct ErrorDescriptor<'tcx> {
146 goal: Goal<'tcx, ty::Predicate<'tcx>>,
147 index: Option<usize>, }
149
150 let mut error_map: FxIndexMap<_, Vec<_>> = self
151 .reported_trait_errors
152 .borrow()
153 .iter()
154 .map(|(&span, goals)| {
155 (span, goals.0.iter().map(|&goal| ErrorDescriptor { goal, index: None }).collect())
156 })
157 .collect();
158
159 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
164 enum ErrorSortKey {
165 SubtypeFormat(usize, usize),
166 OtherKind,
167 SizedTrait,
168 MetaSizedTrait,
169 PointeeSizedTrait,
170 Coerce,
171 WellFormed,
172 }
173 errors.sort_by_key(|e| {
174 let maybe_sizedness_did = match e.obligation.predicate.kind().skip_binder() {
175 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred.def_id()),
176 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => Some(pred.def_id()),
177 _ => None,
178 };
179
180 match e.obligation.predicate.kind().skip_binder() {
181 ty::PredicateKind::Subtype(_)
182 if matches!(
183 e.obligation.cause.span.desugaring_kind(),
184 Some(DesugaringKind::FormatLiteral { .. })
185 ) =>
186 {
187 let (_, row, col, ..) =
188 self.tcx.sess.source_map().span_to_location_info(e.obligation.cause.span);
189 ErrorSortKey::SubtypeFormat(row, col)
190 }
191 _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => {
192 ErrorSortKey::SizedTrait
193 }
194 _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => {
195 ErrorSortKey::MetaSizedTrait
196 }
197 _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => {
198 ErrorSortKey::PointeeSizedTrait
199 }
200 ty::PredicateKind::Coerce(_) => ErrorSortKey::Coerce,
201 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
202 ErrorSortKey::WellFormed
203 }
204 _ => ErrorSortKey::OtherKind,
205 }
206 });
207
208 for (index, error) in errors.iter().enumerate() {
209 let mut span = error.obligation.cause.span;
212 let expn_data = span.ctxt().outer_expn_data();
213 if let ExpnKind::Desugaring(_) = expn_data.kind {
214 span = expn_data.call_site;
215 }
216
217 error_map
218 .entry(span)
219 .or_default()
220 .push(ErrorDescriptor { goal: error.obligation.as_goal(), index: Some(index) });
221 }
222
223 let mut is_suppressed = vec![false; errors.len()];
226 for (_, error_set) in error_map.iter() {
227 for error in error_set {
229 if let Some(index) = error.index {
230 for error2 in error_set {
234 if error2.index.is_some_and(|index2| is_suppressed[index2]) {
235 continue;
239 }
240
241 if self.error_implies(error2.goal, error.goal)
242 && !(error2.index >= error.index
243 && self.error_implies(error.goal, error2.goal))
244 {
245 info!("skipping {:?} (implied by {:?})", error, error2);
246 is_suppressed[index] = true;
247 break;
248 }
249 }
250 }
251 }
252 }
253
254 let mut reported = None;
255 for from_expansion in [false, true] {
256 for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
257 if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
258 if !error.references_error() {
259 let guar = self.report_fulfillment_error(error);
260 self.infcx.set_tainted_by_errors(guar);
261 reported = Some(guar);
262 let mut span = error.obligation.cause.span;
265 let expn_data = span.ctxt().outer_expn_data();
266 if let ExpnKind::Desugaring(_) = expn_data.kind {
267 span = expn_data.call_site;
268 }
269 self.reported_trait_errors
270 .borrow_mut()
271 .entry(span)
272 .or_insert_with(|| (vec![], guar))
273 .0
274 .push(error.obligation.as_goal());
275 }
276 if let Some(guar) = self.dcx().has_errors() {
277 self.infcx.set_tainted_by_errors(guar);
278 }
279 }
280 }
281 }
282
283 reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
287 }
288
289 #[instrument(skip(self), level = "debug")]
290 fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
291 let mut error = FulfillmentError {
292 obligation: error.obligation.clone(),
293 code: error.code.clone(),
294 root_obligation: error.root_obligation.clone(),
295 };
296 if matches!(
297 error.code,
298 FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
299 | FulfillmentErrorCode::Project(_)
300 ) && self.apply_do_not_recommend(&mut error.obligation)
301 {
302 error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
303 }
304
305 match error.code {
306 FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
307 error.obligation.clone(),
308 &error.root_obligation,
309 selection_error,
310 ),
311 FulfillmentErrorCode::Project(ref e) => {
312 self.report_projection_error(&error.obligation, e)
313 }
314 FulfillmentErrorCode::Ambiguity { overflow: None } => {
315 self.maybe_report_ambiguity(&error.obligation)
316 }
317 FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
318 self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
319 }
320 FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
321 .report_mismatched_types(
322 &error.obligation.cause,
323 error.obligation.param_env,
324 expected_found.expected,
325 expected_found.found,
326 *err,
327 )
328 .emit(),
329 FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
330 let mut diag = self.report_mismatched_consts(
331 &error.obligation.cause,
332 error.obligation.param_env,
333 expected_found.expected,
334 expected_found.found,
335 *err,
336 );
337 let code = error.obligation.cause.code().peel_derives().peel_match_impls();
338 if let ObligationCauseCode::WhereClause(..)
339 | ObligationCauseCode::WhereClauseInExpr(..) = code
340 {
341 self.note_obligation_cause_code(
342 error.obligation.cause.body_id,
343 &mut diag,
344 error.obligation.predicate,
345 error.obligation.param_env,
346 code,
347 &mut vec![],
348 &mut Default::default(),
349 );
350 }
351 diag.emit()
352 }
353 FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
354 }
355 }
356
357 fn extern_crates_with_the_same_name(
361 &self,
362 expected_def_id: DefId,
363 trait_def_id: DefId,
364 ) -> bool {
365 if expected_def_id.is_local() || trait_def_id.is_local() {
366 return false;
367 }
368 match (
372 self.tcx.extern_crate(expected_def_id.krate),
373 self.tcx.extern_crate(trait_def_id.krate),
374 ) {
375 (
376 Some(ExternCrate {
377 src: ExternCrateSource::Extern(expected_def_id),
378 dependency_of: LOCAL_CRATE,
379 ..
380 }),
381 Some(ExternCrate {
382 src: ExternCrateSource::Extern(trait_def_id),
383 dependency_of: LOCAL_CRATE,
384 ..
385 }),
386 ) => self.tcx.item_name(expected_def_id) == self.tcx.item_name(trait_def_id),
387 _ => false,
388 }
389 }
390
391 pub fn check_same_definition_different_crate<F>(
392 &self,
393 err: &mut Diag<'_>,
394 expected_did: DefId,
395 found_dids: impl Iterator<Item = DefId>,
396 get_impls: F,
397 ty: &str,
398 ) -> bool
399 where
400 F: Fn(DefId) -> Vec<Span>,
401 {
402 let krate = self.tcx.crate_name(expected_did.krate);
403 let name = self.tcx.item_name(expected_did);
404 let definitions_with_same_path: UnordSet<_> = found_dids
405 .filter(|def_id| {
406 def_id.krate != expected_did.krate
407 && (self.extern_crates_with_the_same_name(expected_did, *def_id)
408 || self.tcx.crate_name(def_id.krate) == krate)
409 && self.tcx.item_name(def_id) == name
410 })
411 .map(|def_id| (self.tcx.def_path_str(def_id), def_id))
412 .collect();
413
414 let definitions_with_same_path =
415 definitions_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p);
416 let mut suggested = false;
417 let mut trait_is_impl = false;
418
419 if !definitions_with_same_path.is_empty() {
420 let mut span: MultiSpan = self.tcx.def_span(expected_did).into();
421 span.push_span_label(
422 self.tcx.def_span(expected_did),
423 format!("this is the expected {ty}"),
424 );
425 suggested = true;
426 for (_, definition_with_same_path) in &definitions_with_same_path {
427 let definitions_impls = get_impls(*definition_with_same_path);
428 if definitions_impls.is_empty() {
429 continue;
430 }
431
432 for candidate_span in definitions_impls {
433 span.push_span_label(candidate_span, format!("this is the found {ty}"));
434 trait_is_impl = true;
435 }
436 }
437 if !trait_is_impl {
438 for (_, def_id) in definitions_with_same_path {
439 span.push_span_label(
440 self.tcx.def_span(def_id),
441 format!("this is the {ty} that was imported"),
442 );
443 }
444 }
445 self.note_two_crate_versions(expected_did, span, err);
446 err.help("you can use `cargo tree` to explore your dependency tree");
447 }
448 suggested
449 }
450}
451
452pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
455 use std::fmt::Write;
456
457 let trait_ref = tcx.impl_opt_trait_ref(impl_def_id)?.instantiate_identity();
458 let mut w = "impl".to_owned();
459
460 #[derive(Debug, Default)]
461 struct SizednessFound {
462 sized: bool,
463 meta_sized: bool,
464 }
465
466 let mut types_with_sizedness_bounds = FxIndexMap::<_, SizednessFound>::default();
467
468 let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
469
470 let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
471 if !arg_names.is_empty() {
472 w.push('<');
473 w.push_str(&arg_names.join(", "));
474 w.push('>');
475
476 for ty in args.types() {
477 types_with_sizedness_bounds.insert(ty, SizednessFound::default());
479 }
480 }
481
482 write!(
483 w,
484 " {}{} for {}",
485 tcx.impl_polarity(impl_def_id).as_str(),
486 trait_ref.print_only_trait_path(),
487 tcx.type_of(impl_def_id).instantiate_identity()
488 )
489 .unwrap();
490
491 let predicates = tcx.predicates_of(impl_def_id).predicates;
492 let mut pretty_predicates = Vec::with_capacity(predicates.len());
493
494 let sized_trait = tcx.lang_items().sized_trait();
495 let meta_sized_trait = tcx.lang_items().meta_sized_trait();
496
497 for (p, _) in predicates {
498 if let Some(trait_clause) = p.as_trait_clause() {
500 let self_ty = trait_clause.self_ty().skip_binder();
501 let sizedness_of = types_with_sizedness_bounds.entry(self_ty).or_default();
502 if Some(trait_clause.def_id()) == sized_trait {
503 sizedness_of.sized = true;
504 continue;
505 } else if Some(trait_clause.def_id()) == meta_sized_trait {
506 sizedness_of.meta_sized = true;
507 continue;
508 }
509 }
510
511 pretty_predicates.push(p.to_string());
512 }
513
514 for (ty, sizedness) in types_with_sizedness_bounds {
515 if !tcx.features().sized_hierarchy() {
516 if sizedness.sized {
517 } else {
519 pretty_predicates.push(format!("{ty}: ?Sized"));
520 }
521 } else {
522 if sizedness.sized {
523 pretty_predicates.push(format!("{ty}: Sized"));
525 } else if sizedness.meta_sized {
526 pretty_predicates.push(format!("{ty}: MetaSized"));
527 } else {
528 pretty_predicates.push(format!("{ty}: PointeeSized"));
529 }
530 }
531 }
532
533 if !pretty_predicates.is_empty() {
534 write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
535 }
536
537 w.push(';');
538 Some(w)
539}
540
541impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
542 pub fn report_extra_impl_obligation(
543 &self,
544 error_span: Span,
545 impl_item_def_id: LocalDefId,
546 trait_item_def_id: DefId,
547 requirement: &dyn fmt::Display,
548 ) -> Diag<'a> {
549 let mut err = struct_span_code_err!(
550 self.dcx(),
551 error_span,
552 E0276,
553 "impl has stricter requirements than trait"
554 );
555
556 if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) {
557 if let Some(span) = self.tcx.hir_span_if_local(trait_item_def_id) {
558 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
559 err.span_label(span, format!("definition of `{item_name}` from trait"));
560 }
561 }
562
563 err.span_label(error_span, format!("impl has extra requirement {requirement}"));
564
565 err
566 }
567}
568
569pub fn report_dyn_incompatibility<'tcx>(
570 tcx: TyCtxt<'tcx>,
571 span: Span,
572 hir_id: Option<hir::HirId>,
573 trait_def_id: DefId,
574 violations: &[DynCompatibilityViolation],
575) -> Diag<'tcx> {
576 let trait_str = tcx.def_path_str(trait_def_id);
577 let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
578 hir::Node::Item(item) => match item.kind {
579 hir::ItemKind::Trait(_, _, _, ident, ..)
580 | hir::ItemKind::TraitAlias(_, ident, _, _) => Some(ident.span),
581 _ => unreachable!(),
582 },
583 _ => None,
584 });
585
586 let mut err = struct_span_code_err!(
587 tcx.dcx(),
588 span,
589 E0038,
590 "the {} `{}` is not dyn compatible",
591 tcx.def_descr(trait_def_id),
592 trait_str
593 );
594 err.span_label(span, format!("`{trait_str}` is not dyn compatible"));
595
596 attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err);
597
598 let mut reported_violations = FxIndexSet::default();
599 let mut multi_span = vec![];
600 let mut messages = vec![];
601 for violation in violations {
602 if let DynCompatibilityViolation::SizedSelf(sp) = &violation
603 && !sp.is_empty()
604 {
605 reported_violations.insert(DynCompatibilityViolation::SizedSelf(vec![].into()));
608 }
609 if reported_violations.insert(violation.clone()) {
610 let spans = violation.spans();
611 let msg = if trait_span.is_none() || spans.is_empty() {
612 format!("the trait is not dyn compatible because {}", violation.error_msg())
613 } else {
614 format!("...because {}", violation.error_msg())
615 };
616 if spans.is_empty() {
617 err.note(msg);
618 } else {
619 for span in spans {
620 multi_span.push(span);
621 messages.push(msg.clone());
622 }
623 }
624 }
625 }
626 let has_multi_span = !multi_span.is_empty();
627 let mut note_span = MultiSpan::from_spans(multi_span.clone());
628 if let (Some(trait_span), true) = (trait_span, has_multi_span) {
629 note_span.push_span_label(trait_span, "this trait is not dyn compatible...");
630 }
631 for (span, msg) in iter::zip(multi_span, messages) {
632 note_span.push_span_label(span, msg);
633 }
634 err.span_note(
635 note_span,
636 "for a trait to be dyn compatible it needs to allow building a vtable\n\
637 for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>",
638 );
639
640 if trait_span.is_some() {
642 let mut potential_solutions: Vec<_> =
643 reported_violations.into_iter().map(|violation| violation.solution()).collect();
644 potential_solutions.sort();
645 potential_solutions.dedup();
647 for solution in potential_solutions {
648 solution.add_to(&mut err);
649 }
650 }
651
652 attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err);
653
654 err
655}
656
657fn attempt_dyn_to_enum_suggestion(
660 tcx: TyCtxt<'_>,
661 trait_def_id: DefId,
662 trait_str: &str,
663 err: &mut Diag<'_>,
664) {
665 let impls_of = tcx.trait_impls_of(trait_def_id);
666
667 if !impls_of.blanket_impls().is_empty() {
668 return;
669 }
670
671 let concrete_impls: Option<Vec<Ty<'_>>> = impls_of
672 .non_blanket_impls()
673 .values()
674 .flatten()
675 .map(|impl_id| {
676 let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
679
680 match impl_type.kind() {
685 ty::Str | ty::Slice(_) | ty::Dynamic(_, _) => {
686 return None;
687 }
688 _ => {}
689 }
690 Some(impl_type)
691 })
692 .collect();
693 let Some(concrete_impls) = concrete_impls else { return };
694
695 const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9;
696 if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM {
697 return;
698 }
699
700 let externally_visible = if let Some(def_id) = trait_def_id.as_local() {
701 tcx.resolutions(()).effective_visibilities.is_exported(def_id)
705 } else {
706 false
707 };
708
709 if let [only_impl] = &concrete_impls[..] {
710 let within = if externally_visible { " within this crate" } else { "" };
711 err.help(with_no_trimmed_paths!(format!(
712 "only type `{only_impl}` implements `{trait_str}`{within}; \
713 consider using it directly instead."
714 )));
715 } else {
716 let types = concrete_impls
717 .iter()
718 .map(|t| with_no_trimmed_paths!(format!(" {}", t)))
719 .collect::<Vec<String>>()
720 .join("\n");
721
722 err.help(format!(
723 "the following types implement `{trait_str}`:\n\
724 {types}\n\
725 consider defining an enum where each variant holds one of these types,\n\
726 implementing `{trait_str}` for this new enum and using it instead",
727 ));
728 }
729
730 if externally_visible {
731 err.note(format!(
732 "`{trait_str}` may be implemented in other crates; if you want to support your users \
733 passing their own types here, you can't refer to a specific type",
734 ));
735 }
736}
737
738fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) {
741 let Some(hir_id) = hir_id else { return };
742 let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return };
743 let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return };
744
745 let Some((_id, first_non_type_parent_node)) =
750 tcx.hir_parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_)))
751 else {
752 return;
753 };
754 if first_non_type_parent_node.fn_sig().is_none() {
755 return;
756 }
757
758 err.span_suggestion_verbose(
759 ty.span.until(trait_ref.span),
760 "consider using an opaque type instead",
761 "impl ",
762 Applicability::MaybeIncorrect,
763 );
764}