mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 01:04:03 +00:00
Add a couple helpers, make return types less confusing
This commit is contained in:
parent
a6727bad88
commit
118730b9a3
@ -305,15 +305,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
|||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
sig.to_coroutine_given_kind_and_upvars(
|
coroutine_closure_to_certain_coroutine(
|
||||||
tcx,
|
tcx,
|
||||||
args.parent_args(),
|
|
||||||
tcx.coroutine_for_closure(def_id),
|
|
||||||
goal_kind,
|
goal_kind,
|
||||||
// No captures by ref, so this doesn't matter.
|
// No captures by ref, so this doesn't matter.
|
||||||
tcx.lifetimes.re_static,
|
tcx.lifetimes.re_static,
|
||||||
args.tupled_upvars_ty(),
|
def_id,
|
||||||
args.coroutine_captures_by_ref_ty(),
|
args,
|
||||||
|
sig,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Closure kind is not yet determined, so we return ambiguity unless
|
// Closure kind is not yet determined, so we return ambiguity unless
|
||||||
@ -322,33 +321,13 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let async_fn_kind_trait_def_id =
|
coroutine_closure_to_ambiguous_coroutine(
|
||||||
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
|
||||||
let upvars_projection_def_id = tcx
|
|
||||||
.associated_items(async_fn_kind_trait_def_id)
|
|
||||||
.filter_by_name_unhygienic(sym::Upvars)
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.def_id;
|
|
||||||
let tupled_upvars_ty = Ty::new_projection(
|
|
||||||
tcx,
|
tcx,
|
||||||
upvars_projection_def_id,
|
goal_kind, // No captures by ref, so this doesn't matter.
|
||||||
[
|
tcx.lifetimes.re_static,
|
||||||
ty::GenericArg::from(kind_ty),
|
def_id,
|
||||||
Ty::from_closure_kind(tcx, goal_kind).into(),
|
args,
|
||||||
// No captures by ref, so this doesn't matter.
|
sig,
|
||||||
tcx.lifetimes.re_static.into(),
|
|
||||||
sig.tupled_inputs_ty.into(),
|
|
||||||
args.tupled_upvars_ty().into(),
|
|
||||||
args.coroutine_captures_by_ref_ty().into(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
sig.to_coroutine(
|
|
||||||
tcx,
|
|
||||||
args.parent_args(),
|
|
||||||
Ty::from_closure_kind(tcx, goal_kind),
|
|
||||||
tcx.coroutine_for_closure(def_id),
|
|
||||||
tupled_upvars_ty,
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -385,6 +364,19 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Relevant types for an async callable, including its inputs, output,
|
||||||
|
/// and the return type you get from awaiting the output.
|
||||||
|
#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)]
|
||||||
|
pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> {
|
||||||
|
pub tupled_inputs_ty: Ty<'tcx>,
|
||||||
|
/// Type returned by calling the closure
|
||||||
|
/// i.e. `f()`.
|
||||||
|
pub output_coroutine_ty: Ty<'tcx>,
|
||||||
|
/// Type returned by `await`ing the output
|
||||||
|
/// i.e. `f().await`.
|
||||||
|
pub coroutine_return_ty: Ty<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
// Returns a binder of the tupled inputs types, output type, and coroutine type
|
// Returns a binder of the tupled inputs types, output type, and coroutine type
|
||||||
// from a builtin coroutine-closure type. If we don't yet know the closure kind of
|
// from a builtin coroutine-closure type. If we don't yet know the closure kind of
|
||||||
// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
|
// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
|
||||||
@ -395,8 +387,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
|||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
goal_kind: ty::ClosureKind,
|
goal_kind: ty::ClosureKind,
|
||||||
env_region: ty::Region<'tcx>,
|
env_region: ty::Region<'tcx>,
|
||||||
) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution>
|
) -> Result<
|
||||||
{
|
(ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec<ty::Predicate<'tcx>>),
|
||||||
|
NoSolution,
|
||||||
|
> {
|
||||||
match *self_ty.kind() {
|
match *self_ty.kind() {
|
||||||
ty::CoroutineClosure(def_id, args) => {
|
ty::CoroutineClosure(def_id, args) => {
|
||||||
let args = args.as_coroutine_closure();
|
let args = args.as_coroutine_closure();
|
||||||
@ -407,24 +401,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
|||||||
if !closure_kind.extends(goal_kind) {
|
if !closure_kind.extends(goal_kind) {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
sig.to_coroutine_given_kind_and_upvars(
|
|
||||||
tcx,
|
coroutine_closure_to_certain_coroutine(
|
||||||
args.parent_args(),
|
tcx, goal_kind, env_region, def_id, args, sig,
|
||||||
tcx.coroutine_for_closure(def_id),
|
|
||||||
goal_kind,
|
|
||||||
env_region,
|
|
||||||
args.tupled_upvars_ty(),
|
|
||||||
args.coroutine_captures_by_ref_ty(),
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let async_fn_kind_trait_def_id =
|
|
||||||
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
|
||||||
let upvars_projection_def_id = tcx
|
|
||||||
.associated_items(async_fn_kind_trait_def_id)
|
|
||||||
.filter_by_name_unhygienic(sym::Upvars)
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.def_id;
|
|
||||||
// When we don't know the closure kind (and therefore also the closure's upvars,
|
// When we don't know the closure kind (and therefore also the closure's upvars,
|
||||||
// which are computed at the same time), we must delay the computation of the
|
// which are computed at the same time), we must delay the computation of the
|
||||||
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
|
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
|
||||||
@ -435,38 +416,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
|||||||
nested.push(
|
nested.push(
|
||||||
ty::TraitRef::new(
|
ty::TraitRef::new(
|
||||||
tcx,
|
tcx,
|
||||||
async_fn_kind_trait_def_id,
|
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None),
|
||||||
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
||||||
)
|
)
|
||||||
.to_predicate(tcx),
|
.to_predicate(tcx),
|
||||||
);
|
);
|
||||||
let tupled_upvars_ty = Ty::new_projection(
|
|
||||||
tcx,
|
coroutine_closure_to_ambiguous_coroutine(
|
||||||
upvars_projection_def_id,
|
tcx, goal_kind, env_region, def_id, args, sig,
|
||||||
[
|
|
||||||
ty::GenericArg::from(kind_ty),
|
|
||||||
Ty::from_closure_kind(tcx, goal_kind).into(),
|
|
||||||
env_region.into(),
|
|
||||||
sig.tupled_inputs_ty.into(),
|
|
||||||
args.tupled_upvars_ty().into(),
|
|
||||||
args.coroutine_captures_by_ref_ty().into(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
sig.to_coroutine(
|
|
||||||
tcx,
|
|
||||||
args.parent_args(),
|
|
||||||
Ty::from_closure_kind(tcx, goal_kind),
|
|
||||||
tcx.coroutine_for_closure(def_id),
|
|
||||||
tupled_upvars_ty,
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
args.coroutine_closure_sig().rebind((
|
args.coroutine_closure_sig().rebind(AsyncCallableRelevantTypes {
|
||||||
sig.tupled_inputs_ty,
|
tupled_inputs_ty: sig.tupled_inputs_ty,
|
||||||
sig.return_ty,
|
output_coroutine_ty: coroutine_ty,
|
||||||
coroutine_ty,
|
coroutine_return_ty: sig.return_ty,
|
||||||
)),
|
}),
|
||||||
nested,
|
nested,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -490,7 +456,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
|||||||
.def_id;
|
.def_id;
|
||||||
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
||||||
Ok((
|
Ok((
|
||||||
bound_sig.rebind((Ty::new_tup(tcx, sig.inputs()), sig.output(), future_output_ty)),
|
bound_sig.rebind(AsyncCallableRelevantTypes {
|
||||||
|
tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()),
|
||||||
|
output_coroutine_ty: sig.output(),
|
||||||
|
coroutine_return_ty: future_output_ty,
|
||||||
|
}),
|
||||||
nested,
|
nested,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -541,7 +511,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.def_id;
|
.def_id;
|
||||||
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
||||||
Ok((bound_sig.rebind((sig.inputs()[0], sig.output(), future_output_ty)), nested))
|
Ok((
|
||||||
|
bound_sig.rebind(AsyncCallableRelevantTypes {
|
||||||
|
tupled_inputs_ty: sig.inputs()[0],
|
||||||
|
output_coroutine_ty: sig.output(),
|
||||||
|
coroutine_return_ty: future_output_ty,
|
||||||
|
}),
|
||||||
|
nested,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Bool
|
ty::Bool
|
||||||
@ -574,6 +551,68 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a coroutine-closure, project to its returned coroutine when we are *certain*
|
||||||
|
/// that the closure's kind is compatible with the goal.
|
||||||
|
fn coroutine_closure_to_certain_coroutine<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
goal_kind: ty::ClosureKind,
|
||||||
|
goal_region: ty::Region<'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
args: ty::CoroutineClosureArgs<'tcx>,
|
||||||
|
sig: ty::CoroutineClosureSignature<'tcx>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
sig.to_coroutine_given_kind_and_upvars(
|
||||||
|
tcx,
|
||||||
|
args.parent_args(),
|
||||||
|
tcx.coroutine_for_closure(def_id),
|
||||||
|
goal_kind,
|
||||||
|
goal_region,
|
||||||
|
args.tupled_upvars_ty(),
|
||||||
|
args.coroutine_captures_by_ref_ty(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a coroutine-closure, project to its returned coroutine when we are *not certain*
|
||||||
|
/// that the closure's kind is compatible with the goal, and therefore also don't know
|
||||||
|
/// yet what the closure's upvars are.
|
||||||
|
///
|
||||||
|
/// Note that we do not also push a `AsyncFnKindHelper` goal here.
|
||||||
|
fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
goal_kind: ty::ClosureKind,
|
||||||
|
goal_region: ty::Region<'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
args: ty::CoroutineClosureArgs<'tcx>,
|
||||||
|
sig: ty::CoroutineClosureSignature<'tcx>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
let async_fn_kind_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
||||||
|
let upvars_projection_def_id = tcx
|
||||||
|
.associated_items(async_fn_kind_trait_def_id)
|
||||||
|
.filter_by_name_unhygienic(sym::Upvars)
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.def_id;
|
||||||
|
let tupled_upvars_ty = Ty::new_projection(
|
||||||
|
tcx,
|
||||||
|
upvars_projection_def_id,
|
||||||
|
[
|
||||||
|
ty::GenericArg::from(args.kind_ty()),
|
||||||
|
Ty::from_closure_kind(tcx, goal_kind).into(),
|
||||||
|
goal_region.into(),
|
||||||
|
sig.tupled_inputs_ty.into(),
|
||||||
|
args.tupled_upvars_ty().into(),
|
||||||
|
args.coroutine_captures_by_ref_ty().into(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
sig.to_coroutine(
|
||||||
|
tcx,
|
||||||
|
args.parent_args(),
|
||||||
|
Ty::from_closure_kind(tcx, goal_kind),
|
||||||
|
tcx.coroutine_for_closure(def_id),
|
||||||
|
tupled_upvars_ty,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Assemble a list of predicates that would be present on a theoretical
|
/// Assemble a list of predicates that would be present on a theoretical
|
||||||
/// user impl for an object type. These predicates must be checked any time
|
/// user impl for an object type. These predicates must be checked any time
|
||||||
/// we assemble a built-in object candidate for an object type, since they
|
/// we assemble a built-in object candidate for an object type, since they
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::traits::{check_args_compatible, specialization_graph};
|
use crate::traits::{check_args_compatible, specialization_graph};
|
||||||
|
|
||||||
|
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
|
||||||
use super::assembly::{self, structural_traits, Candidate};
|
use super::assembly::{self, structural_traits, Candidate};
|
||||||
use super::{EvalCtxt, GoalSource};
|
use super::{EvalCtxt, GoalSource};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
@ -392,46 +393,56 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
goal_kind,
|
goal_kind,
|
||||||
env_region,
|
env_region,
|
||||||
)?;
|
)?;
|
||||||
let output_is_sized_pred =
|
let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
|
||||||
tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| {
|
|AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| {
|
||||||
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
|
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_ty])
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let pred = tupled_inputs_and_output_and_coroutine
|
let pred = tupled_inputs_and_output_and_coroutine
|
||||||
.map_bound(|(inputs, output, coroutine)| {
|
.map_bound(
|
||||||
let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) {
|
|AsyncCallableRelevantTypes {
|
||||||
sym::CallOnceFuture => (
|
tupled_inputs_ty,
|
||||||
ty::AliasTy::new(
|
output_coroutine_ty,
|
||||||
tcx,
|
coroutine_return_ty,
|
||||||
goal.predicate.def_id(),
|
}| {
|
||||||
[goal.predicate.self_ty(), inputs],
|
let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) {
|
||||||
|
sym::CallOnceFuture => (
|
||||||
|
ty::AliasTy::new(
|
||||||
|
tcx,
|
||||||
|
goal.predicate.def_id(),
|
||||||
|
[goal.predicate.self_ty(), tupled_inputs_ty],
|
||||||
|
),
|
||||||
|
output_coroutine_ty.into(),
|
||||||
),
|
),
|
||||||
coroutine.into(),
|
sym::CallMutFuture | sym::CallFuture => (
|
||||||
),
|
ty::AliasTy::new(
|
||||||
sym::CallMutFuture | sym::CallFuture => (
|
tcx,
|
||||||
ty::AliasTy::new(
|
goal.predicate.def_id(),
|
||||||
tcx,
|
[
|
||||||
goal.predicate.def_id(),
|
ty::GenericArg::from(goal.predicate.self_ty()),
|
||||||
[
|
tupled_inputs_ty.into(),
|
||||||
ty::GenericArg::from(goal.predicate.self_ty()),
|
env_region.into(),
|
||||||
inputs.into(),
|
],
|
||||||
env_region.into(),
|
),
|
||||||
],
|
output_coroutine_ty.into(),
|
||||||
),
|
),
|
||||||
coroutine.into(),
|
sym::Output => (
|
||||||
),
|
ty::AliasTy::new(
|
||||||
sym::Output => (
|
tcx,
|
||||||
ty::AliasTy::new(
|
goal.predicate.def_id(),
|
||||||
tcx,
|
[
|
||||||
goal.predicate.def_id(),
|
ty::GenericArg::from(goal.predicate.self_ty()),
|
||||||
[ty::GenericArg::from(goal.predicate.self_ty()), inputs.into()],
|
tupled_inputs_ty.into(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
coroutine_return_ty.into(),
|
||||||
),
|
),
|
||||||
output.into(),
|
name => bug!("no such associated type: {name}"),
|
||||||
),
|
};
|
||||||
name => bug!("no such associated type: {name}"),
|
ty::ProjectionPredicate { projection_ty, term }
|
||||||
};
|
},
|
||||||
ty::ProjectionPredicate { projection_ty, term }
|
)
|
||||||
})
|
|
||||||
.to_predicate(tcx);
|
.to_predicate(tcx);
|
||||||
|
|
||||||
// A built-in `AsyncFn` impl only holds if the output is sized.
|
// A built-in `AsyncFn` impl only holds if the output is sized.
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use crate::traits::supertrait_def_ids;
|
use crate::traits::supertrait_def_ids;
|
||||||
|
|
||||||
|
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
|
||||||
use super::assembly::{self, structural_traits, Candidate};
|
use super::assembly::{self, structural_traits, Candidate};
|
||||||
use super::{EvalCtxt, GoalSource, SolverMode};
|
use super::{EvalCtxt, GoalSource, SolverMode};
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
@ -327,14 +328,19 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
// This region doesn't matter because we're throwing away the coroutine type
|
// This region doesn't matter because we're throwing away the coroutine type
|
||||||
tcx.lifetimes.re_static,
|
tcx.lifetimes.re_static,
|
||||||
)?;
|
)?;
|
||||||
let output_is_sized_pred =
|
let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
|
||||||
tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| {
|
|AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
|
||||||
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
|
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_coroutine_ty])
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let pred = tupled_inputs_and_output_and_coroutine
|
let pred = tupled_inputs_and_output_and_coroutine
|
||||||
.map_bound(|(inputs, _, _)| {
|
.map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
|
||||||
ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
|
ty::TraitRef::new(
|
||||||
|
tcx,
|
||||||
|
goal.predicate.def_id(),
|
||||||
|
[goal.predicate.self_ty(), tupled_inputs_ty],
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.to_predicate(tcx);
|
.to_predicate(tcx);
|
||||||
// A built-in `AsyncFn` impl only holds if the output is sized.
|
// A built-in `AsyncFn` impl only holds if the output is sized.
|
||||||
|
Loading…
Reference in New Issue
Block a user