make the gat wfcheck algorithm a loop

This commit is contained in:
Michael Goulet 2022-02-11 00:17:22 -08:00
parent 852a851712
commit 477459795d

View File

@ -266,7 +266,8 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
/// ```
fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) {
let mut required_bounds_by_item = FxHashMap::default();
loop {
let mut should_continue = false;
for gat_item in associated_items {
let gat_def_id = gat_item.id.def_id;
let gat_item = tcx.associated_item(gat_def_id);
@ -306,15 +307,28 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
gat_generics,
)
}
hir::AssocItemKind::Type => gather_gat_bounds(
hir::AssocItemKind::Type => {
// If our associated item is a GAT with missing bounds, add them to
// the param-env here. This allows this GAT to propagate missing bounds
// to other GATs.
let param_env = augment_param_env(
tcx,
param_env,
required_bounds_by_item.get(&item_def_id),
);
gather_gat_bounds(
tcx,
param_env,
item_hir_id,
tcx.explicit_item_bounds(item_def_id).iter().copied().collect::<Vec<_>>(),
tcx.explicit_item_bounds(item_def_id)
.iter()
.copied()
.collect::<Vec<_>>(),
&FxHashSet::default(),
gat_def_id,
gat_generics,
),
)
}
hir::AssocItemKind::Const => None,
};
@ -330,8 +344,18 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
}
}
if let Some(required_bounds) = new_required_bounds {
required_bounds_by_item.insert(gat_def_id, required_bounds);
if let Some(new_required_bounds) = new_required_bounds {
let required_bounds = required_bounds_by_item.entry(gat_def_id).or_default();
if new_required_bounds != *required_bounds {
*required_bounds = new_required_bounds;
// Iterate until our required_bounds no longer change
// Since they changed here, we should continue the loop
should_continue = true;
}
}
}
if !should_continue {
break;
}
}
@ -398,6 +422,28 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
}
}
/// Add a new set of predicates to the caller_bounds of an existing param_env,
/// and normalize the param_env afterwards
fn augment_param_env<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
new_predicates: Option<&FxHashSet<ty::Predicate<'tcx>>>,
) -> ty::ParamEnv<'tcx> {
let Some(new_predicates) = new_predicates else {
return param_env;
};
if new_predicates.is_empty() {
return param_env;
}
let bounds =
tcx.mk_predicates(param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()));
// FIXME(compiler-errors): Perhaps there is a case where we need to normalize this
// i.e. traits::normalize_param_env_or_error
ty::ParamEnv::new(bounds, param_env.reveal(), param_env.constness())
}
fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,