Support default-body trait functions with RPITIT
This commit is contained in:
parent
d4846f9d03
commit
21047f1a1c
3 changed files with 60 additions and 6 deletions
|
@ -340,10 +340,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
if in_trait {
|
if in_trait {
|
||||||
span_bug!(item.span, "impl-trait in trait has no default")
|
assert!(tcx.impl_defaultness(owner).has_value());
|
||||||
} else {
|
|
||||||
find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
|
|
||||||
}
|
}
|
||||||
|
find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
|
||||||
}
|
}
|
||||||
ItemKind::Trait(..)
|
ItemKind::Trait(..)
|
||||||
| ItemKind::TraitAlias(..)
|
| ItemKind::TraitAlias(..)
|
||||||
|
|
|
@ -71,7 +71,15 @@ enum ProjectionCandidate<'tcx> {
|
||||||
/// From an "impl" (or a "pseudo-impl" returned by select)
|
/// From an "impl" (or a "pseudo-impl" returned by select)
|
||||||
Select(Selection<'tcx>),
|
Select(Selection<'tcx>),
|
||||||
|
|
||||||
ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
|
ImplTraitInTrait(ImplTraitInTraitCandidate<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
|
enum ImplTraitInTraitCandidate<'tcx> {
|
||||||
|
// The `impl Trait` from a trait function's default body
|
||||||
|
Trait,
|
||||||
|
// A concrete type provided from a trait's `impl Trait` from an impl
|
||||||
|
Impl(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ProjectionCandidateSet<'tcx> {
|
enum ProjectionCandidateSet<'tcx> {
|
||||||
|
@ -1317,6 +1325,17 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
|
||||||
) {
|
) {
|
||||||
let tcx = selcx.tcx();
|
let tcx = selcx.tcx();
|
||||||
if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
|
if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
|
||||||
|
// If we are trying to project an RPITIT with the _identity_ substs,
|
||||||
|
// then we must be within a default trait body.
|
||||||
|
if obligation.predicate.substs
|
||||||
|
== ty::InternalSubsts::identity_for_item(tcx, obligation.predicate.item_def_id)
|
||||||
|
{
|
||||||
|
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
|
||||||
|
ImplTraitInTraitCandidate::Trait,
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
|
let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
|
||||||
let trait_def_id = tcx.parent(trait_fn_def_id);
|
let trait_def_id = tcx.parent(trait_fn_def_id);
|
||||||
let trait_substs =
|
let trait_substs =
|
||||||
|
@ -1329,7 +1348,9 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
|
||||||
let _ =
|
let _ =
|
||||||
selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
|
selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
|
||||||
Ok(Some(super::ImplSource::UserDefined(data))) => {
|
Ok(Some(super::ImplSource::UserDefined(data))) => {
|
||||||
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
|
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
|
||||||
|
ImplTraitInTraitCandidate::Impl(data),
|
||||||
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
|
@ -1792,9 +1813,18 @@ fn confirm_candidate<'cx, 'tcx>(
|
||||||
ProjectionCandidate::Select(impl_source) => {
|
ProjectionCandidate::Select(impl_source) => {
|
||||||
confirm_select_candidate(selcx, obligation, impl_source)
|
confirm_select_candidate(selcx, obligation, impl_source)
|
||||||
}
|
}
|
||||||
ProjectionCandidate::ImplTraitInTrait(data) => {
|
ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Impl(data)) => {
|
||||||
confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
|
confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
|
||||||
}
|
}
|
||||||
|
// If we're projecting an RPITIT for a default trait body, that's just
|
||||||
|
// the same def-id, but as an opaque type (with regular RPIT semantics).
|
||||||
|
ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Trait) => Progress {
|
||||||
|
term: selcx
|
||||||
|
.tcx()
|
||||||
|
.mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
|
||||||
|
.into(),
|
||||||
|
obligations: vec![],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// When checking for cycle during evaluation, we compare predicates with
|
// When checking for cycle during evaluation, we compare predicates with
|
||||||
|
@ -2212,6 +2242,16 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
|
||||||
return Progress { term: tcx.ty_error().into(), obligations };
|
return Progress { term: tcx.ty_error().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: tcx
|
||||||
|
.mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
|
||||||
|
.into(),
|
||||||
|
obligations,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let impl_fn_def_id = leaf_def.item.def_id;
|
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 impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
|
||||||
|
|
||||||
|
|
15
src/test/ui/impl-trait/in-trait/default-body.rs
Normal file
15
src/test/ui/impl-trait/in-trait/default-body.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// check-pass
|
||||||
|
// edition:2021
|
||||||
|
|
||||||
|
#![feature(return_position_impl_trait_in_trait)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
async fn baz() -> impl Debug {
|
||||||
|
Self::baz().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue