|
| 1 | +use rustc_ast::BoundPolarity; |
1 | 2 | use rustc_hir::{self as hir, AmbigArg}; |
2 | 3 | use rustc_infer::infer::TyCtxtInferExt; |
3 | 4 | use rustc_macros::{LintDiagnostic, Subdiagnostic}; |
@@ -66,6 +67,33 @@ declare_lint! { |
66 | 67 |
|
67 | 68 | declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); |
68 | 69 |
|
| 70 | +/// Check if an opaque type has an explicit `?Sized` bound by examining its HIR bounds. |
| 71 | +fn opaque_has_maybe_sized_bound<'tcx>( |
| 72 | + cx: &LateContext<'tcx>, |
| 73 | + opaque_def_id: rustc_span::def_id::DefId, |
| 74 | +) -> bool { |
| 75 | + let Some(local_def_id) = opaque_def_id.as_local() else { |
| 76 | + return false; |
| 77 | + }; |
| 78 | + |
| 79 | + let opaque_ty = match cx.tcx.hir_node_by_def_id(local_def_id) { |
| 80 | + hir::Node::OpaqueTy(opaque) => opaque, |
| 81 | + _ => return false, |
| 82 | + }; |
| 83 | + |
| 84 | + // Check if any of the bounds is a `?Sized` bound |
| 85 | + for bound in opaque_ty.bounds { |
| 86 | + if let hir::GenericBound::Trait(poly_trait_ref) = bound |
| 87 | + && matches!(poly_trait_ref.modifiers.polarity, BoundPolarity::Maybe(_)) |
| 88 | + && cx.tcx.is_lang_item(poly_trait_ref.trait_ref.path.res.def_id(), hir::LangItem::Sized) |
| 89 | + { |
| 90 | + return true; |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + false |
| 95 | +} |
| 96 | + |
69 | 97 | impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { |
70 | 98 | fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { |
71 | 99 | let hir::TyKind::OpaqueDef(opaque) = &ty.kind else { |
@@ -98,12 +126,14 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { |
98 | 126 | let Some(proj_term) = proj.term.as_type() else { return }; |
99 | 127 |
|
100 | 128 | // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"... |
| 129 | + // unless the nested opaque has an explicit `?Sized` bound. |
101 | 130 | if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind() |
102 | 131 | && cx.tcx.parent(opaque_ty.def_id) == def_id |
103 | 132 | && matches!( |
104 | 133 | opaque.origin, |
105 | 134 | hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } |
106 | 135 | ) |
| 136 | + && !opaque_has_maybe_sized_bound(cx, opaque_ty.def_id) |
107 | 137 | { |
108 | 138 | return; |
109 | 139 | } |
|
0 commit comments