Skip to content

Commit 8487833

Browse files
authored
Rollup merge of #91849 - jackh726:gats-outlives-lint-part2, r=nikomatsakis
GATs outlives lint: Try to prove bounds Fixes #91036 Fixes #90888 Fixes #91348 (better error + documentation to be added to linked issue) Instead of checking for bounds directly, try to prove them in the associated type environment. Also, add a bit of extra information to the error, including a link to the relevant discussion issue (#87479). That should be edited to include a brief summary of the current state of the outlives lint, including a brief background. It also might or might not be worth it to bump this to a full error code at some point. r? ``@nikomatsakis``
2 parents f8de2f5 + 4897415 commit 8487833

File tree

7 files changed

+157
-50
lines changed

7 files changed

+157
-50
lines changed

compiler/rustc_infer/src/infer/free_regions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_middle::ty::{self, Lift, Region, TyCtxt};
1111
///
1212
/// This stuff is a bit convoluted and should be refactored, but as we
1313
/// transition to NLL, it'll all go away anyhow.
14-
pub struct RegionRelations<'a, 'tcx> {
14+
pub(crate) struct RegionRelations<'a, 'tcx> {
1515
pub tcx: TyCtxt<'tcx>,
1616

1717
/// The context used for debug messages

compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use std::fmt;
2828
/// assuming such values can be found. It returns the final values of
2929
/// all the variables as well as a set of errors that must be reported.
3030
#[instrument(level = "debug", skip(region_rels, var_infos, data))]
31-
pub fn resolve<'tcx>(
31+
pub(crate) fn resolve<'tcx>(
3232
region_rels: &RegionRelations<'_, 'tcx>,
3333
var_infos: VarInfos,
3434
data: RegionConstraintData<'tcx>,

compiler/rustc_typeck/src/check/wfcheck.rs

+46-8
Original file line numberDiff line numberDiff line change
@@ -426,22 +426,48 @@ fn check_gat_where_clauses(
426426
}
427427
}
428428

429-
// If there are any missing clauses, emit an error
430-
let mut clauses = clauses.unwrap_or_default();
429+
// If there are any clauses that aren't provable, emit an error
430+
let clauses = clauses.unwrap_or_default();
431431
debug!(?clauses);
432432
if !clauses.is_empty() {
433-
let written_predicates: ty::GenericPredicates<'_> =
434-
tcx.explicit_predicates_of(trait_item.def_id);
433+
let param_env = tcx.param_env(trait_item.def_id);
434+
435435
let mut clauses: Vec<_> = clauses
436-
.drain_filter(|clause| !written_predicates.predicates.iter().any(|p| &p.0 == clause))
436+
.into_iter()
437+
.filter(|clause| match clause.kind().skip_binder() {
438+
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
439+
!region_known_to_outlive(
440+
tcx,
441+
trait_item.hir_id(),
442+
param_env,
443+
&FxHashSet::default(),
444+
a,
445+
b,
446+
)
447+
}
448+
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
449+
!ty_known_to_outlive(
450+
tcx,
451+
trait_item.hir_id(),
452+
param_env,
453+
&FxHashSet::default(),
454+
a,
455+
b,
456+
)
457+
}
458+
_ => bug!("Unexpected PredicateKind"),
459+
})
437460
.map(|clause| format!("{}", clause))
438461
.collect();
462+
439463
// We sort so that order is predictable
440464
clauses.sort();
465+
441466
if !clauses.is_empty() {
467+
let plural = if clauses.len() > 1 { "s" } else { "" };
442468
let mut err = tcx.sess.struct_span_err(
443469
trait_item.span,
444-
&format!("Missing required bounds on {}", trait_item.ident),
470+
&format!("missing required bound{} on `{}`", plural, trait_item.ident),
445471
);
446472

447473
let suggestion = format!(
@@ -455,11 +481,22 @@ fn check_gat_where_clauses(
455481
);
456482
err.span_suggestion(
457483
trait_item.generics.where_clause.tail_span_for_suggestion(),
458-
"add the required where clauses",
484+
&format!("add the required where clause{}", plural),
459485
suggestion,
460486
Applicability::MachineApplicable,
461487
);
462488

489+
let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" };
490+
err.note(&format!(
491+
"{} currently required to ensure that impls have maximum flexibility",
492+
bound
493+
));
494+
err.note(
495+
"we are soliciting feedback, see issue #87479 \
496+
<https://github.com/rust-lang/rust/issues/87479> \
497+
for more information",
498+
);
499+
463500
err.emit()
464501
}
465502
}
@@ -541,7 +578,8 @@ fn region_known_to_outlive<'tcx>(
541578
});
542579

543580
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
544-
(&infcx).push_sub_region_constraint(origin, region_a, region_b);
581+
// `region_a: region_b` -> `region_b <= region_a`
582+
(&infcx).push_sub_region_constraint(origin, region_b, region_a);
545583

546584
let errors = infcx.resolve_regions(
547585
id.expect_owner().to_def_id(),

src/test/ui/generic-associated-types/issue-86787.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ enum Either<L, R> {
99
pub trait HasChildrenOf {
1010
type T;
1111
type TRef<'a>;
12-
//~^ Missing required bounds
12+
//~^ missing required
1313

1414
fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>>;
1515
fn take_children(self) -> Vec<Self::T>;
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
error: Missing required bounds on TRef
1+
error: missing required bound on `TRef`
22
--> $DIR/issue-86787.rs:11:5
33
|
44
LL | type TRef<'a>;
55
| ^^^^^^^^^^^^^-
66
| |
7-
| help: add the required where clauses: `where Self: 'a`
7+
| help: add the required where clause: `where Self: 'a`
8+
|
9+
= note: this bound is currently required to ensure that impls have maximum flexibility
10+
= note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
811

912
error: aborting due to previous error
1013

src/test/ui/generic-associated-types/self-outlives-lint.rs

+32-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::fmt::Debug;
77
// We have a `&'a self`, so we need a `Self: 'a`
88
trait Iterable {
99
type Item<'x>;
10-
//~^ Missing required bounds
10+
//~^ missing required
1111
fn iter<'a>(&'a self) -> Self::Item<'a>;
1212
}
1313

@@ -23,7 +23,7 @@ impl<T> Iterable for T {
2323
// We have a `&'a T`, so we need a `T: 'x`
2424
trait Deserializer<T> {
2525
type Out<'x>;
26-
//~^ Missing required bounds
26+
//~^ missing required
2727
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
2828
}
2929

@@ -37,14 +37,14 @@ impl<T> Deserializer<T> for () {
3737
// We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x`
3838
trait Deserializer2<T> {
3939
type Out<'x>;
40-
//~^ Missing required bounds
40+
//~^ missing required
4141
fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>;
4242
}
4343

4444
// We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y`
4545
trait Deserializer3<T, U> {
4646
type Out<'x, 'y>;
47-
//~^ Missing required bounds
47+
//~^ missing required
4848
fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
4949
}
5050

@@ -59,7 +59,7 @@ struct Wrap<T>(T);
5959
// We pass `Wrap<T>` and we see `&'z Wrap<T>`, so we require `D: 'x`
6060
trait Des {
6161
type Out<'x, D>;
62-
//~^ Missing required bounds
62+
//~^ missing required
6363
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
6464
}
6565
/*
@@ -75,7 +75,7 @@ impl Des for () {
7575
// implied bound that `T: 'z`, so we require `D: 'x`
7676
trait Des2 {
7777
type Out<'x, D>;
78-
//~^ Missing required bounds
78+
//~^ missing required
7979
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>;
8080
}
8181
/*
@@ -90,7 +90,7 @@ impl Des2 for () {
9090
// We see `&'z T`, so we require `D: 'x`
9191
trait Des3 {
9292
type Out<'x, D>;
93-
//~^ Missing required bounds
93+
//~^ missing required
9494
fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>;
9595
}
9696
/*
@@ -112,22 +112,22 @@ trait NoGat<'a> {
112112
// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
113113
trait TraitLifetime<'a> {
114114
type Bar<'b>;
115-
//~^ Missing required bounds
115+
//~^ missing required
116116
fn method(&'a self) -> Self::Bar<'a>;
117117
}
118118

119119
// Like above, but we have a where clause that can prove what we want
120120
// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
121121
trait TraitLifetimeWhere<'a> where Self: 'a {
122122
type Bar<'b>;
123-
//~^ Missing required bounds
123+
//~^ missing required
124124
fn method(&'a self) -> Self::Bar<'a>;
125125
}
126126

127127
// Explicit bound instead of implicit; we want to still error
128128
trait ExplicitBound {
129129
type Bar<'b>;
130-
//~^ Missing required bounds
130+
//~^ missing required
131131
fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b;
132132
}
133133

@@ -141,14 +141,15 @@ trait NotInReturn {
141141
trait IterableTwo {
142142
type Item<'a>;
143143
type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
144-
//~^ Missing required bounds
144+
//~^ missing required
145145
fn iter<'a>(&'a self) -> Self::Iterator<'a>;
146146
}
147147

148-
// We also should report region outlives clauses
148+
// We also should report region outlives clauses. Here, we know that `'y: 'x`,
149+
// because of `&'x &'y`, so we require that `'b: 'a`.
149150
trait RegionOutlives {
150151
type Bar<'a, 'b>;
151-
//~^ Missing required bounds
152+
//~^ missing required
152153
fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>;
153154
}
154155

@@ -161,6 +162,17 @@ impl Foo for () {
161162
}
162163
*/
163164

165+
// Similar to the above, except with explicit bounds
166+
trait ExplicitRegionOutlives<'ctx> {
167+
type Fut<'out>;
168+
//~^ missing required
169+
170+
fn test<'out>(ctx: &'ctx i32) -> Self::Fut<'out>
171+
where
172+
'ctx: 'out;
173+
}
174+
175+
164176
// If there are multiple methods that return the GAT, require a set of clauses
165177
// that can be satisfied by *all* methods
166178
trait MultipleMethods {
@@ -170,4 +182,11 @@ trait MultipleMethods {
170182
fn gimme_default(&self) -> Self::Bar<'static>;
171183
}
172184

185+
// We would normally require `Self: 'a`, but we can prove that `Self: 'static`
186+
// because of the the bounds on the trait, so the bound is proven
187+
trait Trait: 'static {
188+
type Assoc<'a>;
189+
fn make_assoc(_: &u32) -> Self::Assoc<'_>;
190+
}
191+
173192
fn main() {}

0 commit comments

Comments
 (0)