make the gat wfcheck algorithm a loop
This commit is contained in:
parent
852a851712
commit
477459795d
@ -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>,
|
||||
|
Loading…
x
Reference in New Issue
Block a user