Skip to content

Commit 82148cd

Browse files
committed
Change outlives clause checking algorithm
1 parent a8c44d3 commit 82148cd

File tree

5 files changed

+137
-106
lines changed

5 files changed

+137
-106
lines changed

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,16 +1255,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12551255
self.tainted_by_errors_flag.set(true)
12561256
}
12571257

1258-
/// Process the region constraints and report any errors that
1258+
/// Process the region constraints and return any any errors that
12591259
/// result. After this, no more unification operations should be
12601260
/// done -- or the compiler will panic -- but it is legal to use
12611261
/// `resolve_vars_if_possible` as well as `fully_resolve`.
1262-
pub fn resolve_regions_and_report_errors(
1262+
pub fn resolve_regions(
12631263
&self,
12641264
region_context: DefId,
12651265
outlives_env: &OutlivesEnvironment<'tcx>,
12661266
mode: RegionckMode,
1267-
) {
1267+
) -> Vec<RegionResolutionError<'tcx>> {
12681268
let (var_infos, data) = {
12691269
let mut inner = self.inner.borrow_mut();
12701270
let inner = &mut *inner;
@@ -1290,6 +1290,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12901290
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
12911291
assert!(old_value.is_none());
12921292

1293+
errors
1294+
}
1295+
1296+
/// Process the region constraints and report any errors that
1297+
/// result. After this, no more unification operations should be
1298+
/// done -- or the compiler will panic -- but it is legal to use
1299+
/// `resolve_vars_if_possible` as well as `fully_resolve`.
1300+
pub fn resolve_regions_and_report_errors(
1301+
&self,
1302+
region_context: DefId,
1303+
outlives_env: &OutlivesEnvironment<'tcx>,
1304+
mode: RegionckMode,
1305+
) {
1306+
let errors = self.resolve_regions(region_context, outlives_env, mode);
1307+
12931308
if !self.is_tainted_by_errors() {
12941309
// As a heuristic, just skip reporting region errors
12951310
// altogether if other errors have been reported while

compiler/rustc_typeck/src/check/regionck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ macro_rules! ignore_err {
104104
};
105105
}
106106

107-
trait OutlivesEnvironmentExt<'tcx> {
107+
pub(crate) trait OutlivesEnvironmentExt<'tcx> {
108108
fn add_implied_bounds(
109109
&mut self,
110110
infcx: &InferCtxt<'a, 'tcx>,

compiler/rustc_typeck/src/check/wfcheck.rs

Lines changed: 110 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
use crate::check::regionck::OutlivesEnvironmentExt;
12
use crate::check::{FnCtxt, Inherited};
23
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
34

4-
use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
55
use rustc_ast as ast;
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@@ -12,7 +12,10 @@ use rustc_hir::intravisit::Visitor;
1212
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
1313
use rustc_hir::lang_items::LangItem;
1414
use rustc_hir::ItemKind;
15+
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
16+
use rustc_infer::infer::outlives::obligations::TypeOutlives;
1517
use rustc_infer::infer::TyCtxtInferExt;
18+
use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
1619
use rustc_middle::hir::map as hir_map;
1720
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
1821
use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -22,7 +25,7 @@ use rustc_middle::ty::{
2225
};
2326
use rustc_session::parse::feature_err;
2427
use rustc_span::symbol::{sym, Ident, Symbol};
25-
use rustc_span::Span;
28+
use rustc_span::{Span, DUMMY_SP};
2629
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
2730
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
2831

@@ -279,84 +282,104 @@ fn check_gat_where_clauses(
279282
return;
280283
}
281284
let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
285+
let mut clauses = FxHashSet::default();
282286
// For every function in this trait...
283287
for item in
284288
associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn))
285289
{
286-
tcx.infer_ctxt().enter(|infcx| {
287-
let sig: ty::Binder<'_, ty::FnSig<'_>> = tcx.fn_sig(item.def_id);
288-
let sig = infcx.replace_bound_vars_with_placeholders(sig);
289-
// Find out what regions are passed as GAT substs
290-
let mut visitor = GATSubstCollector {
291-
tcx,
292-
gat: trait_item.def_id.to_def_id(),
293-
regions: FxHashSet::default(),
294-
_types: FxHashSet::default(),
295-
};
296-
sig.output().visit_with(&mut visitor);
297-
// If there are none, then it nothing to do
298-
if visitor.regions.is_empty() {
299-
return;
300-
}
301-
let mut clauses = FxHashSet::default();
302-
// Otherwise, find the clauses required from implied bounds
303-
for input in sig.inputs() {
304-
// For a given input type, find the implied bounds
305-
let TypeOpOutput { output: bounds, .. } = match ty::ParamEnv::empty()
306-
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty: input })
307-
.fully_perform(&infcx)
308-
{
309-
Ok(o) => o,
310-
Err(_) => continue,
311-
};
312-
debug!(?bounds);
313-
for bound in bounds {
314-
match bound {
315-
traits::query::OutlivesBound::RegionSubParam(r, p) => {
316-
// If the implied bound is a `RegionSubParam` and
317-
// the region is used a GAT subst...
318-
for idx in visitor
319-
.regions
320-
.iter()
321-
.filter(|(proj_r, _)| proj_r == &r)
322-
.map(|r| r.1)
323-
{
324-
// Then create a clause that is required on the GAT
325-
let param_r = tcx.mk_region(ty::RegionKind::ReEarlyBound(
326-
ty::EarlyBoundRegion {
327-
def_id: generics.params[idx].def_id,
328-
index: idx as u32,
329-
name: generics.params[idx].name,
330-
},
331-
));
332-
let clause = ty::PredicateKind::TypeOutlives(
333-
ty::OutlivesPredicate(tcx.mk_ty(ty::Param(p)), param_r),
334-
);
335-
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
336-
clauses.insert(clause);
337-
}
338-
}
339-
_ => {}
340-
}
341-
}
342-
}
343-
// If there are any missing clauses, emit an error
344-
debug!(?clauses);
345-
if !clauses.is_empty() {
346-
let written_predicates: ty::GenericPredicates<'_> =
347-
tcx.predicates_of(trait_item.def_id);
348-
for clause in clauses {
349-
let found =
350-
written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
351-
debug!(?clause, ?found);
352-
let mut error = tcx.sess.struct_span_err(
353-
trait_item.generics.span,
354-
&format!("Missing bound: {}", clause),
290+
let id = hir::HirId::make_owner(item.def_id.expect_local());
291+
let span = DUMMY_SP;
292+
let param_env = tcx.param_env(item.def_id.expect_local());
293+
294+
let sig = tcx.fn_sig(item.def_id);
295+
let sig = tcx.liberate_late_bound_regions(item.def_id, sig);
296+
let mut visitor = GATSubstCollector {
297+
tcx,
298+
gat: trait_item.def_id.to_def_id(),
299+
regions: FxHashSet::default(),
300+
types: FxHashSet::default(),
301+
};
302+
sig.output().visit_with(&mut visitor);
303+
let mut wf_tys = FxHashSet::default();
304+
wf_tys.extend(sig.inputs());
305+
// FIXME: normalize and add normalized inputs?
306+
307+
for (region, region_idx) in &visitor.regions {
308+
for (ty, ty_idx) in &visitor.types {
309+
tcx.infer_ctxt().enter(|infcx| {
310+
let mut outlives_environment = OutlivesEnvironment::new(param_env);
311+
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, span);
312+
outlives_environment.save_implied_bounds(id);
313+
let region_bound_pairs =
314+
outlives_environment.region_bound_pairs_map().get(&id).unwrap();
315+
316+
let cause =
317+
ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
318+
319+
let sup_type = *ty;
320+
let sub_region = region;
321+
322+
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
323+
infer::RelateParamBound(cause.span, sup_type, None)
324+
});
325+
326+
let outlives = &mut TypeOutlives::new(
327+
&infcx,
328+
tcx,
329+
&region_bound_pairs,
330+
Some(tcx.lifetimes.re_root_empty),
331+
param_env,
355332
);
356-
error.emit();
357-
}
333+
outlives.type_must_outlive(origin, sup_type, sub_region);
334+
335+
let errors = infcx.resolve_regions(
336+
trait_item.def_id.to_def_id(),
337+
&outlives_environment,
338+
RegionckMode::default(),
339+
);
340+
341+
debug!(?errors, "errors");
342+
343+
if errors.is_empty() {
344+
debug!(?ty_idx, ?region_idx);
345+
debug!("required clause: {} must outlive {}", ty, region);
346+
let ty_param = generics.param_at(*ty_idx, tcx);
347+
let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
348+
index: ty_param.index,
349+
name: ty_param.name,
350+
}));
351+
let region_param = generics.param_at(*region_idx, tcx);
352+
// Then create a clause that is required on the GAT
353+
let region_param =
354+
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
355+
def_id: region_param.def_id,
356+
index: region_param.index,
357+
name: region_param.name,
358+
}));
359+
let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
360+
ty_param,
361+
region_param,
362+
));
363+
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
364+
clauses.insert(clause);
365+
}
366+
});
358367
}
359-
})
368+
}
369+
}
370+
371+
// If there are any missing clauses, emit an error
372+
debug!(?clauses);
373+
if !clauses.is_empty() {
374+
let written_predicates: ty::GenericPredicates<'_> = tcx.predicates_of(trait_item.def_id);
375+
for clause in clauses {
376+
let found = written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
377+
debug!(?clause, ?found);
378+
let mut error = tcx
379+
.sess
380+
.struct_span_err(trait_item.generics.span, &format!("Missing bound: {}", clause));
381+
error.emit();
382+
}
360383
}
361384
}
362385

@@ -366,7 +389,7 @@ struct GATSubstCollector<'tcx> {
366389
// Which region appears and which parameter index its subsituted for
367390
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
368391
// Which params appears and which parameter index its subsituted for
369-
_types: FxHashSet<(Ty<'tcx>, usize)>,
392+
types: FxHashSet<(Ty<'tcx>, usize)>,
370393
}
371394

372395
impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
@@ -375,13 +398,20 @@ impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
375398
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
376399
match t.kind() {
377400
ty::Projection(p) if p.item_def_id == self.gat => {
378-
let (_, substs) = p.trait_ref_and_own_substs(self.tcx);
379-
self.regions.extend(substs.iter().enumerate().filter_map(|(idx, subst)| {
401+
for (idx, subst) in p.substs.iter().enumerate() {
380402
match subst.unpack() {
381-
GenericArgKind::Lifetime(lt) => Some((lt, idx)),
382-
_ => None,
403+
GenericArgKind::Lifetime(lt) => {
404+
self.regions.insert((lt, idx));
405+
}
406+
GenericArgKind::Type(t) => match t.kind() {
407+
ty::Param(_) => {
408+
self.types.insert((t, idx));
409+
}
410+
_ => {}
411+
},
412+
_ => {}
383413
}
384-
}));
414+
}
385415
}
386416
_ => {}
387417
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,13 @@ trait Deserializer3<T, U> {
4545

4646
trait Deserializer4 {
4747
type Out<'x>;
48-
//~^ Missing bound
4948
fn deserialize<'a, T>(&self, input: &'a T) -> Self::Out<'a>;
5049
}
5150

5251
struct Wrap<T>(T);
5352

5453
trait Des {
5554
type Out<'x, D>;
56-
//~^ Missing bound
5755
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
5856
}
5957
/*
@@ -92,5 +90,5 @@ impl Des3 for () {
9290
}
9391
}
9492
*/
95-
93+
9694
fn main() {}

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

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,29 @@ error: Missing bound: T: 'x
1616
LL | type Out<'x>;
1717
| ^^^^
1818

19-
error: Missing bound: T: 'x
19+
error: Missing bound: U: 'y
2020
--> $DIR/self-outlives-lint.rs:40:13
2121
|
2222
LL | type Out<'x, 'y>;
2323
| ^^^^^^^^
2424

25-
error: Missing bound: U: 'y
25+
error: Missing bound: T: 'x
2626
--> $DIR/self-outlives-lint.rs:40:13
2727
|
2828
LL | type Out<'x, 'y>;
2929
| ^^^^^^^^
3030

31-
error: Missing bound: T: 'x
32-
--> $DIR/self-outlives-lint.rs:47:13
33-
|
34-
LL | type Out<'x>;
35-
| ^^^^
36-
37-
error: Missing bound: T: 'x
38-
--> $DIR/self-outlives-lint.rs:55:13
39-
|
40-
LL | type Out<'x, D>;
41-
| ^^^^^^^
42-
43-
error: Missing bound: T: 'x
44-
--> $DIR/self-outlives-lint.rs:69:13
31+
error: Missing bound: D: 'x
32+
--> $DIR/self-outlives-lint.rs:67:13
4533
|
4634
LL | type Out<'x, D>;
4735
| ^^^^^^^
4836

49-
error: Missing bound: T: 'x
50-
--> $DIR/self-outlives-lint.rs:83:13
37+
error: Missing bound: D: 'x
38+
--> $DIR/self-outlives-lint.rs:81:13
5139
|
5240
LL | type Out<'x, D>;
5341
| ^^^^^^^
5442

55-
error: aborting due to 9 previous errors
43+
error: aborting due to 7 previous errors
5644

0 commit comments

Comments
 (0)