Skip to content

Commit

Permalink
Support default-body trait functions with RPITIT
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Oct 5, 2022
1 parent d4846f9 commit 21047f1
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 6 deletions.
5 changes: 2 additions & 3 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
..
}) => {
if in_trait {
span_bug!(item.span, "impl-trait in trait has no default")
} else {
find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
assert!(tcx.impl_defaultness(owner).has_value());
}
find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
Expand Down
46 changes: 43 additions & 3 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,15 @@ enum ProjectionCandidate<'tcx> {
/// From an "impl" (or a "pseudo-impl" returned by select)
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> {
Expand Down Expand Up @@ -1317,6 +1325,17 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
) {
let tcx = selcx.tcx();
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_def_id = tcx.parent(trait_fn_def_id);
let trait_substs =
Expand All @@ -1329,7 +1348,9 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
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));
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
ImplTraitInTraitCandidate::Impl(data),
));
Ok(())
}
Ok(None) => {
Expand Down Expand Up @@ -1792,9 +1813,18 @@ fn confirm_candidate<'cx, 'tcx>(
ProjectionCandidate::Select(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)
}
// 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
Expand Down Expand Up @@ -2212,6 +2242,16 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
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_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);

Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/impl-trait/in-trait/default-body.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 21047f1

Please sign in to comment.