Rollup merge of #133122 - compiler-errors:afidt, r=oli-obk
Add unpolished, experimental support for AFIDT (async fn in dyn trait)
This allows us to begin messing around `async fn` in `dyn Trait`. Calling an async fn from a trait object always returns a `dyn* Future<Output = ...>`.
To make it work, Implementations are currently required to return something that can be coerced to a `dyn* Future` (see the example in `tests/ui/async-await/dyn/works.rs`). If it's not the right size, then it'll raise an error at the coercion site (see the example in `tests/ui/async-await/dyn/wrong-size.rs`). Currently the only practical way of doing this is wrapping the body in `Box::pin(async move { .. })`.
This PR does not implement a helper type like a "`Boxing`"[^boxing] adapter, and I'll probably follow-up with another PR to improve the error message for the `PointerLike` trait (something that explains in just normal prose what is happening here, rather than a trait error).
[^boxing]: https://rust-lang.github.io/async-fundamentals-initiative/explainer/user_guide_future.html#the-boxing-adapter
This PR also does not implement new trait solver support for AFIDT; I'll need to think how best to integrate it into candidate assembly, and that's a bit of a matter of taste, but I don't think it will be difficult to do.
This could also be generalized:
* To work on functions that are `-> impl Future` (soon).
* To work on functions that are `-> impl Iterator` and other "dyn rpitit safe" traits. We still need to nail down exactly what is needed for this to be okay (not soon).
Tracking:
* https://github.com/rust-lang/rust/issues/133119
This commit is contained in:
@@ -7,8 +7,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
|
||||
use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
|
||||
@@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::symbol::sym;
|
||||
use thin_vec::thin_vec;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::{
|
||||
@@ -61,6 +62,9 @@ enum ProjectionCandidate<'tcx> {
|
||||
/// Bounds specified on an object type
|
||||
Object(ty::PolyProjectionPredicate<'tcx>),
|
||||
|
||||
/// Built-in bound for a dyn async fn in trait
|
||||
ObjectRpitit,
|
||||
|
||||
/// From an "impl" (or a "pseudo-impl" returned by select)
|
||||
Select(Selection<'tcx>),
|
||||
}
|
||||
@@ -827,6 +831,17 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
||||
env_predicates,
|
||||
false,
|
||||
);
|
||||
|
||||
// `dyn Trait` automagically project their AFITs to `dyn* Future`.
|
||||
if tcx.is_impl_trait_in_trait(obligation.predicate.def_id)
|
||||
&& let Some(out_trait_def_id) = data.principal_def_id()
|
||||
&& let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id)
|
||||
&& tcx
|
||||
.supertrait_def_ids(out_trait_def_id)
|
||||
.any(|trait_def_id| trait_def_id == rpitit_trait_def_id)
|
||||
{
|
||||
candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit);
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
@@ -1247,6 +1262,8 @@ fn confirm_candidate<'cx, 'tcx>(
|
||||
ProjectionCandidate::Select(impl_source) => {
|
||||
confirm_select_candidate(selcx, obligation, impl_source)
|
||||
}
|
||||
|
||||
ProjectionCandidate::ObjectRpitit => confirm_object_rpitit_candidate(selcx, obligation),
|
||||
};
|
||||
|
||||
// When checking for cycle during evaluation, we compare predicates with
|
||||
@@ -2034,6 +2051,45 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_object_rpitit_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTermObligation<'tcx>,
|
||||
) -> Progress<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
let mut obligations = thin_vec![];
|
||||
|
||||
// Compute an intersection lifetime for all the input components of this GAT.
|
||||
let intersection =
|
||||
selcx.infcx.next_region_var(RegionVariableOrigin::MiscVariable(obligation.cause.span));
|
||||
for component in obligation.predicate.args {
|
||||
match component.unpack() {
|
||||
ty::GenericArgKind::Lifetime(lt) => {
|
||||
obligations.push(obligation.with(tcx, ty::OutlivesPredicate(lt, intersection)));
|
||||
}
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
obligations.push(obligation.with(tcx, ty::OutlivesPredicate(ty, intersection)));
|
||||
}
|
||||
ty::GenericArgKind::Const(_ct) => {
|
||||
// Consts have no outlives...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Progress {
|
||||
term: Ty::new_dynamic(
|
||||
tcx,
|
||||
tcx.item_bounds_to_existential_predicates(
|
||||
obligation.predicate.def_id,
|
||||
obligation.predicate.args,
|
||||
),
|
||||
intersection,
|
||||
ty::DynStar,
|
||||
)
|
||||
.into(),
|
||||
obligations,
|
||||
}
|
||||
}
|
||||
|
||||
// Get obligations corresponding to the predicates from the where-clause of the
|
||||
// associated type itself.
|
||||
fn assoc_ty_own_obligations<'cx, 'tcx>(
|
||||
|
||||
Reference in New Issue
Block a user