Implement projection for ImplTraitPlaceholder
This commit is contained in:
parent
d34cb98fb0
commit
4265ef8cb2
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user