Skip to content

Commit 426424b

Browse files
Make it a lint for all opaque types
1 parent d0d6af9 commit 426424b

16 files changed

+237
-147
lines changed

compiler/rustc_error_messages/locales/en-US/lint.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,6 @@ lint_check_name_warning = {$msg}
434434
435435
lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
436436
437-
lint_rpit_hidden_inferred_bound = return-position `{$ty}` does not satisfy its associated type bounds
437+
lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds
438438
.specifically = this associated type bound is unsatisfied for `{$proj_ty}`
439439
.suggestion = add this bound

compiler/rustc_lint/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ mod non_ascii_idents;
6262
mod non_fmt_panic;
6363
mod nonstandard_style;
6464
mod noop_method_call;
65+
mod opaque_hidden_inferred_bound;
6566
mod pass_by_value;
6667
mod passes;
6768
mod redundant_semicolon;
68-
mod rpit_hidden_inferred_bound;
6969
mod traits;
7070
mod types;
7171
mod unused;
@@ -94,9 +94,9 @@ use non_ascii_idents::*;
9494
use non_fmt_panic::NonPanicFmt;
9595
use nonstandard_style::*;
9696
use noop_method_call::*;
97+
use opaque_hidden_inferred_bound::*;
9798
use pass_by_value::*;
9899
use redundant_semicolon::*;
99-
use rpit_hidden_inferred_bound::*;
100100
use traits::*;
101101
use types::*;
102102
use unused::*;
@@ -225,7 +225,7 @@ macro_rules! late_lint_mod_passes {
225225
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
226226
InvalidAtomicOrdering: InvalidAtomicOrdering,
227227
NamedAsmLabels: NamedAsmLabels,
228-
RpitHiddenInferredBound: RpitHiddenInferredBound,
228+
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
229229
]
230230
);
231231
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use rustc_hir as hir;
2+
use rustc_infer::infer::TyCtxtInferExt;
3+
use rustc_macros::LintDiagnostic;
4+
use rustc_middle::ty::{self, fold::BottomUpFolder, Ty, TypeFoldable};
5+
use rustc_span::Span;
6+
use rustc_trait_selection::traits;
7+
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
8+
9+
use crate::{LateContext, LateLintPass, LintContext};
10+
11+
declare_lint! {
12+
/// The `opaque_hidden_inferred_bound` lint detects cases in which nested
13+
/// `impl Trait` in associated type bounds are not written generally enough
14+
/// to satisfy the bounds of the associated type. This functionality was
15+
/// removed in #97346, but then rolled back in #99860 because it was made
16+
/// into a hard error too quickly.
17+
///
18+
/// We plan on reintroducing this as a hard error, but in the mean time, this
19+
/// lint serves to warn and suggest fixes for any use-cases which rely on this
20+
/// behavior.
21+
pub OPAQUE_HIDDEN_INFERRED_BOUND,
22+
Warn,
23+
"detects the use of nested `impl Trait` types in associated type bounds that are not general enough"
24+
}
25+
26+
declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
27+
28+
impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
29+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
30+
let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
31+
let def_id = item.def_id.def_id.to_def_id();
32+
cx.tcx.infer_ctxt().enter(|ref infcx| {
33+
// For every projection predicate in the opaque type's explicit bounds,
34+
// check that the type that we're assigning actually satisfies the bounds
35+
// of the associated type.
36+
for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) {
37+
// Liberate bound regions in the predicate since we
38+
// don't actually care about lifetimes in this check.
39+
let predicate = cx.tcx.liberate_late_bound_regions(
40+
def_id,
41+
pred.kind(),
42+
);
43+
let ty::PredicateKind::Projection(proj) = predicate else {
44+
continue;
45+
};
46+
// Only check types, since those are the only things that may
47+
// have opaques in them anyways.
48+
let Some(proj_term) = proj.term.ty() else { continue };
49+
50+
let proj_ty =
51+
cx
52+
.tcx
53+
.mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs);
54+
// For every instance of the projection type in the bounds,
55+
// replace them with the term we're assigning to the associated
56+
// type in our opaque type.
57+
let proj_replacer = &mut BottomUpFolder {
58+
tcx: cx.tcx,
59+
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
60+
lt_op: |lt| lt,
61+
ct_op: |ct| ct,
62+
};
63+
// For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
64+
// e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
65+
// with `impl Send: OtherTrait`.
66+
for assoc_pred_and_span in cx
67+
.tcx
68+
.bound_explicit_item_bounds(proj.projection_ty.item_def_id)
69+
.transpose_iter()
70+
{
71+
let assoc_pred_span = assoc_pred_and_span.0.1;
72+
let assoc_pred = assoc_pred_and_span
73+
.map_bound(|(pred, _)| *pred)
74+
.subst(cx.tcx, &proj.projection_ty.substs)
75+
.fold_with(proj_replacer);
76+
let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else {
77+
continue;
78+
};
79+
// If that predicate doesn't hold modulo regions (but passed during type-check),
80+
// then we must've taken advantage of the hack in `project_and_unify_types` where
81+
// we replace opaques with inference vars. Emit a warning!
82+
if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
83+
traits::ObligationCause::dummy(),
84+
cx.param_env,
85+
assoc_pred,
86+
)) {
87+
// If it's a trait bound and an opaque that doesn't satisfy it,
88+
// then we can emit a suggestion to add the bound.
89+
let (suggestion, suggest_span) =
90+
match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
91+
(ty::Opaque(def_id, _), ty::PredicateKind::Trait(trait_pred)) => (
92+
format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
93+
Some(cx.tcx.def_span(def_id).shrink_to_hi()),
94+
),
95+
_ => (String::new(), None),
96+
};
97+
cx.emit_spanned_lint(
98+
OPAQUE_HIDDEN_INFERRED_BOUND,
99+
pred_span,
100+
OpaqueHiddenInferredBoundLint {
101+
ty: cx.tcx.mk_opaque(def_id, ty::InternalSubsts::identity_for_item(cx.tcx, def_id)),
102+
proj_ty: proj_term,
103+
assoc_pred_span,
104+
suggestion,
105+
suggest_span,
106+
},
107+
);
108+
}
109+
}
110+
}
111+
});
112+
}
113+
}
114+
115+
#[derive(LintDiagnostic)]
116+
#[diag(lint::opaque_hidden_inferred_bound)]
117+
struct OpaqueHiddenInferredBoundLint<'tcx> {
118+
ty: Ty<'tcx>,
119+
proj_ty: Ty<'tcx>,
120+
#[label(lint::specifically)]
121+
assoc_pred_span: Span,
122+
#[suggestion_verbose(applicability = "machine-applicable", code = "{suggestion}")]
123+
suggest_span: Option<Span>,
124+
suggestion: String,
125+
}

compiler/rustc_lint/src/rpit_hidden_inferred_bound.rs

-143
This file was deleted.

src/test/ui/impl-trait/nested-return-type2-tait.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type Sendable = impl Send;
2626
// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
2727
// type does not implement `Duh`, but if its hidden type does.
2828
fn foo() -> impl Trait<Assoc = Sendable> {
29+
//~^ WARN opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds
2930
|| 42
3031
}
3132

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds
2+
--> $DIR/nested-return-type2-tait.rs:28:24
3+
|
4+
LL | type Assoc: Duh;
5+
| --- this associated type bound is unsatisfied for `Sendable`
6+
...
7+
LL | fn foo() -> impl Trait<Assoc = Sendable> {
8+
| ^^^^^^^^^^^^^^^^
9+
|
10+
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
11+
help: add this bound
12+
|
13+
LL | type Sendable = impl Send + Duh;
14+
| +++++
15+
16+
warning: 1 warning emitted
17+

src/test/ui/impl-trait/nested-return-type2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
2323
// Lazy TAIT would error out, but we inserted a hack to make it work again,
2424
// keeping backwards compatibility.
2525
fn foo() -> impl Trait<Assoc = impl Send> {
26+
//~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
2627
|| 42
2728
}
2829

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
2+
--> $DIR/nested-return-type2.rs:25:24
3+
|
4+
LL | type Assoc: Duh;
5+
| --- this associated type bound is unsatisfied for `impl Send`
6+
...
7+
LL | fn foo() -> impl Trait<Assoc = impl Send> {
8+
| ^^^^^^^^^^^^^^^^^
9+
|
10+
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
11+
help: add this bound
12+
|
13+
LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> {
14+
| +++++
15+
16+
warning: 1 warning emitted
17+

src/test/ui/impl-trait/nested-return-type3-tait.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ impl<F: Duh> Trait for F {
1717
type Sendable = impl Send;
1818

1919
fn foo() -> impl Trait<Assoc = Sendable> {
20+
//~^ WARN opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds
2021
42
2122
}
2223

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds
2+
--> $DIR/nested-return-type3-tait.rs:19:24
3+
|
4+
LL | type Assoc: Duh;
5+
| --- this associated type bound is unsatisfied for `Sendable`
6+
...
7+
LL | fn foo() -> impl Trait<Assoc = Sendable> {
8+
| ^^^^^^^^^^^^^^^^
9+
|
10+
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
11+
help: add this bound
12+
|
13+
LL | type Sendable = impl Send + Duh;
14+
| +++++
15+
16+
warning: 1 warning emitted
17+

src/test/ui/impl-trait/nested-return-type3-tait2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ impl<F: Duh> Trait for F {
1616

1717
type Sendable = impl Send;
1818
type Traitable = impl Trait<Assoc = Sendable>;
19+
//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds
1920

2021
fn foo() -> Traitable {
2122
42

0 commit comments

Comments
 (0)