Implement projection for ImplTraitPlaceholder

This commit is contained in:
Michael Goulet 2022-08-31 04:41:16 +00:00
parent d34cb98fb0
commit 4265ef8cb2
2 changed files with 120 additions and 1 deletions

View File

@ -2038,7 +2038,9 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
// Visibility on them should have no effect, but to avoid the visibility
// query failing on some items, we provide it for opaque types as well.
| Node::Item(hir::Item {
kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..),
kind: hir::ItemKind::Use(_, hir::UseKind::ListStem)
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::ImplTraitPlaceholder(..),
..
}) => ty::Visibility::Restricted(tcx.parent_module(hir_id)),
// Visibilities of trait impl items are inherited from their traits

View File

@ -32,6 +32,7 @@ use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym;
@ -70,6 +71,8 @@ enum ProjectionCandidate<'tcx> {
/// From an "impl" (or a "pseudo-impl" returned by select)
Select(Selection<'tcx>),
ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
}
enum ProjectionCandidateSet<'tcx> {
@ -1265,6 +1268,8 @@ 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.
@ -1303,6 +1308,48 @@ fn project<'cx, 'tcx>(
}
}
/// 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.
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.item_def_id) == DefKind::ImplTraitPlaceholder {
let trait_fn_def_id = tcx.parent(obligation.predicate.item_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));
// FIXME(named-returns): Binders
let trait_predicate =
ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs })
.to_poly_trait_predicate();
let _ =
selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
Ok(Some(super::ImplSource::UserDefined(data))) => {
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
Ok(())
}
Ok(None) => {
candidate_set.mark_ambiguous();
return Err(());
}
Ok(Some(_)) => {
// Don't know enough about the impl to provide a useful signature
return Err(());
}
Err(e) => {
debug!(error = ?e, "selection error");
candidate_set.mark_error(e);
return 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.
@ -1745,6 +1792,9 @@ 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
@ -2107,6 +2157,73 @@ 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.parent(obligation.predicate.item_def_id);
let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else {
return Progress { term: tcx.ty_error().into(), obligations };
};
if !leaf_def.item.defaultness(tcx).has_value() {
return Progress { term: tcx.ty_error().into(), obligations };
}
let impl_fn_def_id = leaf_def.item.def_id;
let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
let sig = tcx
.bound_fn_sig(impl_fn_def_id)
.map_bound(|fn_sig| tcx.liberate_late_bound_regions(impl_fn_def_id, fn_sig))
.subst(tcx, impl_fn_substs);
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(std::iter::zip(predicates.predicates, predicates.spans).map(
|(pred, span)| {
Obligation::with_depth(
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 = super::normalize_to(
selcx,
obligation.param_env,
cause.clone(),
sig.output(),
&mut obligations,
);
Progress { term: ty.into(), obligations }
}
// Get obligations corresponding to the predicates from the where-clause of the
// associated type itself.
// Note: `feature(generic_associated_types)` is required to write such