Replace RPITIT current impl with new strategy that lowers as a GAT

This commit is contained in:
Santiago Pastorino 2023-06-24 00:00:08 -03:00
parent d1389b9b48
commit 20429af7a3
No known key found for this signature in database
GPG key ID: 8131A24E0C79EFAF
146 changed files with 1106 additions and 586 deletions

View file

@ -131,8 +131,6 @@ enum ProjectionCandidate<'tcx> {
/// From an "impl" (or a "pseudo-impl" returned by select)
Select(Selection<'tcx>),
ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
}
enum ProjectionCandidateSet<'tcx> {
@ -1472,8 +1470,6 @@ fn project<'cx, 'tcx>(
let mut candidates = ProjectionCandidateSet::None;
assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates);
// Make sure that the following procedures are kept in order. ParamEnv
// needs to be first because it has highest priority, and Select checks
// the return value of push_candidate which assumes it's ran at last.
@ -1499,7 +1495,7 @@ fn project<'cx, 'tcx>(
ProjectionCandidateSet::None => {
let tcx = selcx.tcx();
let term = match tcx.def_kind(obligation.predicate.def_id) {
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => Ty::new_projection(
DefKind::AssocTy => Ty::new_projection(
tcx,
obligation.predicate.def_id,
obligation.predicate.substs,
@ -1530,47 +1526,6 @@ fn project<'cx, 'tcx>(
}
}
/// If the predicate's item is an `ImplTraitPlaceholder`, we do a select on the
/// corresponding trait ref. If this yields an `impl`, then we're able to project
/// to a concrete type, since we have an `impl`'s method to provide the RPITIT.
fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
let tcx = selcx.tcx();
if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
let trait_def_id = tcx.parent(trait_fn_def_id);
let trait_substs =
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
let trait_predicate = ty::TraitRef::new(tcx, trait_def_id, trait_substs);
let _ = selcx.infcx.commit_if_ok(|_| {
match selcx.select(&obligation.with(tcx, trait_predicate)) {
Ok(Some(super::ImplSource::UserDefined(data))) => {
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
Ok(())
}
Ok(None) => {
candidate_set.mark_ambiguous();
Err(())
}
Ok(Some(_)) => {
// Don't know enough about the impl to provide a useful signature
Err(())
}
Err(e) => {
debug!(error = ?e, "selection error");
candidate_set.mark_error(e);
Err(())
}
}
});
}
}
/// The first thing we have to do is scan through the parameter
/// environment to see whether there are any projection predicates
/// there that can answer this question.
@ -1739,11 +1694,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
// Can't assemble candidate from impl for RPITIT
if selcx.tcx().def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
return;
}
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
let trait_ref = obligation.predicate.trait_ref(selcx.tcx());
@ -2012,9 +1962,6 @@ fn confirm_candidate<'cx, 'tcx>(
ProjectionCandidate::Select(impl_source) => {
confirm_select_candidate(selcx, obligation, impl_source)
}
ProjectionCandidate::ImplTraitInTrait(data) => {
confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
}
};
// When checking for cycle during evaluation, we compare predicates with
@ -2240,8 +2187,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
let ty::Closure(_, substs) =
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
let ty::Closure(_, substs) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
else {
unreachable!()
};
@ -2419,103 +2365,6 @@ fn confirm_impl_candidate<'cx, 'tcx>(
}
}
fn confirm_impl_trait_in_trait_candidate<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
let tcx = selcx.tcx();
let mut obligations = data.nested;
let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) {
Ok(assoc_ty) => assoc_ty,
Err(guar) => return Progress::error(tcx, guar),
};
// We don't support specialization for RPITITs anyways... yet.
// Also don't try to project to an RPITIT that has no value
if !leaf_def.is_final() || !leaf_def.item.defaultness(tcx).has_value() {
return Progress { term: Ty::new_misc_error(tcx).into(), obligations };
}
// Use the default `impl Trait` for the trait, e.g., for a default trait body
if leaf_def.item.container == ty::AssocItemContainer::TraitContainer {
return Progress {
term: Ty::new_opaque(tcx, obligation.predicate.def_id, obligation.predicate.substs)
.into(),
obligations,
};
}
// Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
// since `data.substs` are the impl substs.
let impl_fn_substs =
obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
let impl_fn_substs = translate_substs(
selcx.infcx,
obligation.param_env,
data.impl_def_id,
impl_fn_substs,
leaf_def.defining_node,
);
if !check_substs_compatible(tcx, leaf_def.item, impl_fn_substs) {
let err = Ty::new_error_with_message(
tcx,
obligation.cause.span,
"impl method and trait method have different parameters",
);
return Progress { term: err.into(), obligations };
}
let impl_fn_def_id = leaf_def.item.def_id;
let cause = ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
super::ItemObligation(impl_fn_def_id),
);
let predicates = normalize_with_depth_to(
selcx,
obligation.param_env,
cause.clone(),
obligation.recursion_depth + 1,
tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs),
&mut obligations,
);
obligations.extend(predicates.into_iter().map(|(pred, span)| {
Obligation::with_depth(
tcx,
ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
if span.is_dummy() {
super::ItemObligation(impl_fn_def_id)
} else {
super::BindingObligation(impl_fn_def_id, span)
},
),
obligation.recursion_depth + 1,
obligation.param_env,
pred,
)
}));
let ty = normalize_with_depth_to(
selcx,
obligation.param_env,
cause.clone(),
obligation.recursion_depth + 1,
tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else(
|guar| Ty::new_error(tcx, guar),
|tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs),
),
&mut obligations,
);
Progress { term: ty.into(), obligations }
}
// Get obligations corresponding to the predicates from the where-clause of the
// associated type itself.
fn assoc_ty_own_obligations<'cx, 'tcx>(