Properly drain pending obligations for coroutines
This commit is contained in:
parent
67df5b9cfa
commit
169955f3be
19 changed files with 242 additions and 64 deletions
|
|
@ -163,6 +163,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Resume type defaults to `()` if the coroutine has no argument.
|
||||
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
|
||||
|
||||
// TODO: In the new solver, we can just instantiate this eagerly
|
||||
// with the witness. This will ensure that goals that don't need
|
||||
// to stall on interior types will get processed eagerly.
|
||||
let interior = self.next_ty_var(expr_span);
|
||||
self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior));
|
||||
|
||||
|
|
|
|||
|
|
@ -659,10 +659,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
obligations.extend(ok.obligations);
|
||||
}
|
||||
|
||||
// FIXME: Use a real visitor for unstalled obligations in the new solver.
|
||||
if !coroutines.is_empty() {
|
||||
obligations
|
||||
.extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
|
||||
obligations.extend(
|
||||
self.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.drain_stalled_obligations_for_coroutines(&self.infcx),
|
||||
);
|
||||
}
|
||||
|
||||
self.typeck_results
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
|
|||
let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner;
|
||||
|
||||
let infcx =
|
||||
tcx.infer_ctxt().ignoring_regions().build(TypingMode::analysis_in_body(tcx, def_id));
|
||||
tcx.infer_ctxt().ignoring_regions().build(TypingMode::typeck_for_body(tcx, def_id));
|
||||
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
|
||||
|
||||
TypeckRootCtxt {
|
||||
|
|
|
|||
|
|
@ -967,7 +967,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
|
||||
debug_assert!(!self.next_trait_solver());
|
||||
match self.typing_mode() {
|
||||
TypingMode::Analysis { defining_opaque_types }
|
||||
TypingMode::Analysis { defining_opaque_types, stalled_generators: _ }
|
||||
| TypingMode::Borrowck { defining_opaque_types } => {
|
||||
id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
|
||||
}
|
||||
|
|
@ -1262,7 +1262,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// to handle them without proper canonicalization. This means we may cause cycle
|
||||
// errors and fail to reveal opaques while inside of bodies. We should rename this
|
||||
// function and require explicit comments on all use-sites in the future.
|
||||
ty::TypingMode::Analysis { defining_opaque_types: _ }
|
||||
ty::TypingMode::Analysis { defining_opaque_types: _, stalled_generators: _ }
|
||||
| ty::TypingMode::Borrowck { defining_opaque_types: _ } => {
|
||||
TypingMode::non_body_analysis()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
|
|||
/// Among all pending obligations, collect those are stalled on a inference variable which has
|
||||
/// changed since the last call to `select_where_possible`. Those obligations are marked as
|
||||
/// successful and returned.
|
||||
fn drain_unstalled_obligations(
|
||||
fn drain_stalled_obligations_for_coroutines(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
) -> PredicateObligations<'tcx>;
|
||||
|
|
|
|||
|
|
@ -387,6 +387,15 @@ rustc_queries! {
|
|||
}
|
||||
}
|
||||
|
||||
query stalled_generators_within(
|
||||
key: LocalDefId
|
||||
) -> &'tcx ty::List<LocalDefId> {
|
||||
desc {
|
||||
|tcx| "computing the opaque types defined by `{}`",
|
||||
tcx.def_path_str(key.to_def_id())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the explicitly user-written *bounds* on the associated or opaque type given by `DefId`
|
||||
/// that must be proven true at definition site (and which can be assumed at usage sites).
|
||||
///
|
||||
|
|
|
|||
|
|
@ -366,11 +366,11 @@ macro_rules! define_callbacks {
|
|||
|
||||
pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>;
|
||||
|
||||
// Ensure that keys grow no larger than 80 bytes by accident.
|
||||
// Ensure that keys grow no larger than 96 bytes by accident.
|
||||
// Increase this limit if necessary, but do try to keep the size low if possible
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const _: () = {
|
||||
if size_of::<Key<'static>>() > 88 {
|
||||
if size_of::<Key<'static>>() > 96 {
|
||||
panic!("{}", concat!(
|
||||
"the query `",
|
||||
stringify!($name),
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
) -> Self::PredefinedOpaques {
|
||||
self.mk_predefined_opaques_in_body(data)
|
||||
}
|
||||
type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
|
||||
type LocalDefIds = &'tcx ty::List<LocalDefId>;
|
||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
|
||||
self.mk_canonical_var_infos(infos)
|
||||
|
|
@ -674,9 +674,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.anonymize_bound_vars(binder)
|
||||
}
|
||||
|
||||
fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes {
|
||||
fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::LocalDefIds {
|
||||
self.opaque_types_defined_by(defining_anchor)
|
||||
}
|
||||
|
||||
fn stalled_generators_within(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds {
|
||||
self.stalled_generators_within(defining_anchor)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! bidirectional_lang_item_map {
|
||||
|
|
|
|||
|
|
@ -329,7 +329,10 @@ where
|
|||
TypingMode::Coherence | TypingMode::PostAnalysis => false,
|
||||
// During analysis, opaques are rigid unless they may be defined by
|
||||
// the current body.
|
||||
TypingMode::Analysis { defining_opaque_types: non_rigid_opaques }
|
||||
TypingMode::Analysis {
|
||||
defining_opaque_types: non_rigid_opaques,
|
||||
stalled_generators: _,
|
||||
}
|
||||
| TypingMode::Borrowck { defining_opaque_types: non_rigid_opaques }
|
||||
| TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => {
|
||||
!def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id))
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ where
|
|||
);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
TypingMode::Analysis { defining_opaque_types } => {
|
||||
TypingMode::Analysis { defining_opaque_types, stalled_generators: _ } => {
|
||||
let Some(def_id) = opaque_ty
|
||||
.def_id
|
||||
.as_local()
|
||||
|
|
|
|||
|
|
@ -208,6 +208,21 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
if let ty::CoroutineWitness(def_id, _) = goal.predicate.self_ty().kind() {
|
||||
match ecx.typing_mode() {
|
||||
TypingMode::Analysis { stalled_generators, defining_opaque_types: _ } => {
|
||||
if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
|
||||
{
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
}
|
||||
}
|
||||
TypingMode::Coherence
|
||||
| TypingMode::PostAnalysis
|
||||
| TypingMode::Borrowck { defining_opaque_types: _ }
|
||||
| TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {}
|
||||
}
|
||||
}
|
||||
|
||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,25 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_data_structures::thinvec::ExtractIf;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::{
|
||||
FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode,
|
||||
};
|
||||
use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _};
|
||||
use rustc_span::Span;
|
||||
use tracing::instrument;
|
||||
|
||||
use self::derive_errors::*;
|
||||
use super::Certainty;
|
||||
use super::delegate::SolverDelegate;
|
||||
use super::inspect::{self, ProofTreeInferCtxtExt};
|
||||
use crate::traits::{FulfillmentError, ScrubbedTraitError};
|
||||
|
||||
mod derive_errors;
|
||||
|
|
@ -39,7 +46,7 @@ pub struct FulfillmentCtxt<'tcx, E: 'tcx> {
|
|||
_errors: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
struct ObligationStorage<'tcx> {
|
||||
/// Obligations which resulted in an overflow in fulfillment itself.
|
||||
///
|
||||
|
|
@ -55,20 +62,23 @@ impl<'tcx> ObligationStorage<'tcx> {
|
|||
self.pending.push(obligation);
|
||||
}
|
||||
|
||||
fn has_pending_obligations(&self) -> bool {
|
||||
!self.pending.is_empty() || !self.overflowed.is_empty()
|
||||
}
|
||||
|
||||
fn clone_pending(&self) -> PredicateObligations<'tcx> {
|
||||
let mut obligations = self.pending.clone();
|
||||
obligations.extend(self.overflowed.iter().cloned());
|
||||
obligations
|
||||
}
|
||||
|
||||
fn take_pending(&mut self) -> PredicateObligations<'tcx> {
|
||||
let mut obligations = mem::take(&mut self.pending);
|
||||
obligations.append(&mut self.overflowed);
|
||||
obligations
|
||||
}
|
||||
|
||||
fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'tcx {
|
||||
mem::take(&mut self.pending).into_iter()
|
||||
fn drain_pending(
|
||||
&mut self,
|
||||
cond: impl Fn(&PredicateObligation<'tcx>) -> bool,
|
||||
) -> PredicateObligations<'tcx> {
|
||||
let (unstalled, pending) = mem::take(&mut self.pending).into_iter().partition(cond);
|
||||
self.pending = pending;
|
||||
unstalled
|
||||
}
|
||||
|
||||
fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) {
|
||||
|
|
@ -160,7 +170,7 @@ where
|
|||
}
|
||||
|
||||
let mut has_changed = false;
|
||||
for obligation in self.obligations.unstalled_for_select() {
|
||||
for obligation in self.obligations.drain_pending(|_| true) {
|
||||
let goal = obligation.as_goal();
|
||||
let result = <&SolverDelegate<'tcx>>::from(infcx)
|
||||
.evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
|
||||
|
|
@ -196,15 +206,79 @@ where
|
|||
}
|
||||
|
||||
fn has_pending_obligations(&self) -> bool {
|
||||
!self.obligations.pending.is_empty() || !self.obligations.overflowed.is_empty()
|
||||
self.obligations.has_pending_obligations()
|
||||
}
|
||||
|
||||
fn pending_obligations(&self) -> PredicateObligations<'tcx> {
|
||||
self.obligations.clone_pending()
|
||||
}
|
||||
|
||||
fn drain_unstalled_obligations(&mut self, _: &InferCtxt<'tcx>) -> PredicateObligations<'tcx> {
|
||||
self.obligations.take_pending()
|
||||
fn drain_stalled_obligations_for_coroutines(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
) -> PredicateObligations<'tcx> {
|
||||
self.obligations.drain_pending(|obl| {
|
||||
let stalled_generators = match infcx.typing_mode() {
|
||||
TypingMode::Analysis { defining_opaque_types: _, stalled_generators } => {
|
||||
stalled_generators
|
||||
}
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Borrowck { defining_opaque_types: _ }
|
||||
| TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ }
|
||||
| TypingMode::PostAnalysis => return false,
|
||||
};
|
||||
|
||||
if stalled_generators.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
infcx.probe(|_| {
|
||||
infcx
|
||||
.visit_proof_tree(
|
||||
obl.as_goal(),
|
||||
&mut StalledOnCoroutines { stalled_generators, span: obl.cause.span },
|
||||
)
|
||||
.is_break()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct StalledOnCoroutines<'tcx> {
|
||||
stalled_generators: &'tcx ty::List<LocalDefId>,
|
||||
span: Span,
|
||||
// TODO: Cache
|
||||
}
|
||||
|
||||
impl<'tcx> inspect::ProofTreeVisitor<'tcx> for StalledOnCoroutines<'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn span(&self) -> rustc_span::Span {
|
||||
self.span
|
||||
}
|
||||
|
||||
fn visit_goal(&mut self, inspect_goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
|
||||
inspect_goal.goal().predicate.visit_with(self)?;
|
||||
|
||||
if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
|
||||
candidate.visit_nested_no_probe(self)
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for StalledOnCoroutines<'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
if let ty::CoroutineWitness(def_id, _) = *ty.kind()
|
||||
&& def_id.as_local().is_some_and(|def_id| self.stalled_generators.contains(&def_id))
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,10 +109,16 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>(
|
|||
false,
|
||||
),
|
||||
Ok((_, Certainty::Yes)) => {
|
||||
bug!("did not expect successful goal when collecting ambiguity errors")
|
||||
bug!(
|
||||
"did not expect successful goal when collecting ambiguity errors for `{:?}`",
|
||||
infcx.resolve_vars_if_possible(root_obligation.predicate),
|
||||
)
|
||||
}
|
||||
Err(_) => {
|
||||
bug!("did not expect selection error when collecting ambiguity errors")
|
||||
bug!(
|
||||
"did not expect selection error when collecting ambiguity errors for `{:?}`",
|
||||
infcx.resolve_vars_if_possible(root_obligation.predicate),
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ where
|
|||
let value = value.try_fold_with(&mut folder)?;
|
||||
let goals = folder
|
||||
.fulfill_cx
|
||||
.drain_unstalled_obligations(at.infcx)
|
||||
.drain_stalled_obligations_for_coroutines(at.infcx)
|
||||
.into_iter()
|
||||
.map(|obl| obl.as_goal())
|
||||
.collect();
|
||||
|
|
@ -130,7 +130,7 @@ where
|
|||
);
|
||||
|
||||
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
|
||||
let errors = self.fulfill_cx.select_all_or_error(infcx);
|
||||
let errors = self.fulfill_cx.select_where_possible(infcx);
|
||||
if !errors.is_empty() {
|
||||
return Err(errors);
|
||||
}
|
||||
|
|
@ -171,7 +171,7 @@ where
|
|||
|
||||
let result = if infcx.predicate_may_hold(&obligation) {
|
||||
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
|
||||
let errors = self.fulfill_cx.select_all_or_error(infcx);
|
||||
let errors = self.fulfill_cx.select_where_possible(infcx);
|
||||
if !errors.is_empty() {
|
||||
return Err(errors);
|
||||
}
|
||||
|
|
@ -286,27 +286,31 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
|
|||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let infcx = self.at.infcx;
|
||||
infcx
|
||||
.commit_if_ok(|_| {
|
||||
deeply_normalize_with_skipped_universes(
|
||||
self.at,
|
||||
ty,
|
||||
vec![None; ty.outer_exclusive_binder().as_usize()],
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
|
||||
let result =
|
||||
infcx.commit_if_ok(|_| {
|
||||
deeply_normalize_with_skipped_universes_and_ambiguous_goals::<
|
||||
_,
|
||||
ScrubbedTraitError<'tcx>,
|
||||
>(self.at, ty, vec![None; ty.outer_exclusive_binder().as_usize()])
|
||||
});
|
||||
match result {
|
||||
Ok((ty, _)) => ty,
|
||||
Err(_) => ty.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
let infcx = self.at.infcx;
|
||||
infcx
|
||||
.commit_if_ok(|_| {
|
||||
deeply_normalize_with_skipped_universes(
|
||||
self.at,
|
||||
ct,
|
||||
vec![None; ct.outer_exclusive_binder().as_usize()],
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
|
||||
let result =
|
||||
infcx.commit_if_ok(|_| {
|
||||
deeply_normalize_with_skipped_universes_and_ambiguous_goals::<
|
||||
_,
|
||||
ScrubbedTraitError<'tcx>,
|
||||
>(self.at, ct, vec![None; ct.outer_exclusive_binder().as_usize()])
|
||||
});
|
||||
match result {
|
||||
Ok((ct, _)) => ct,
|
||||
Err(_) => ct.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ where
|
|||
self.select(selcx)
|
||||
}
|
||||
|
||||
fn drain_unstalled_obligations(
|
||||
fn drain_stalled_obligations_for_coroutines(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
) -> PredicateObligations<'tcx> {
|
||||
|
|
|
|||
|
|
@ -1498,7 +1498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// However, if we disqualify *all* goals from being cached, perf suffers.
|
||||
// This is likely fixed by better caching in general in the new solver.
|
||||
// See: <https://github.com/rust-lang/rust/issues/132064>.
|
||||
TypingMode::Analysis { defining_opaque_types }
|
||||
TypingMode::Analysis { defining_opaque_types, stalled_generators: _ }
|
||||
| TypingMode::Borrowck { defining_opaque_types } => {
|
||||
defining_opaque_types.is_empty() || !pred.has_opaque_types()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_middle::query::Providers;
|
||||
|
|
@ -355,6 +356,51 @@ fn opaque_types_defined_by<'tcx>(
|
|||
tcx.mk_local_def_ids(&collector.opaques)
|
||||
}
|
||||
|
||||
pub(super) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { opaque_types_defined_by, ..*providers };
|
||||
// TODO: Move this out of `opaque_types`
|
||||
fn stalled_generators_within<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: LocalDefId,
|
||||
) -> &'tcx ty::List<LocalDefId> {
|
||||
if !tcx.next_trait_solver_globally() {
|
||||
return ty::List::empty();
|
||||
}
|
||||
|
||||
let body = tcx.hir_body_owned_by(item);
|
||||
let mut collector =
|
||||
StalledGeneratorVisitor { tcx, root_def_id: item.to_def_id(), stalled_coroutines: vec![] };
|
||||
collector.visit_body(body);
|
||||
tcx.mk_local_def_ids(&collector.stalled_coroutines)
|
||||
}
|
||||
|
||||
struct StalledGeneratorVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
root_def_id: DefId,
|
||||
stalled_coroutines: Vec<LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for StalledGeneratorVisitor<'tcx> {
|
||||
fn visit_nested_body(&mut self, id: hir::BodyId) {
|
||||
if self.tcx.typeck_root_def_id(self.tcx.hir_body_owner_def_id(id).to_def_id())
|
||||
== self.root_def_id
|
||||
{
|
||||
let body = self.tcx.hir_body(id);
|
||||
self.visit_body(body);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
||||
if let hir::ExprKind::Closure(&hir::Closure {
|
||||
def_id,
|
||||
kind: hir::ClosureKind::Coroutine(_),
|
||||
..
|
||||
}) = ex.kind
|
||||
{
|
||||
self.stalled_coroutines.push(def_id);
|
||||
}
|
||||
intravisit::walk_expr(self, ex);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { opaque_types_defined_by, stalled_generators_within, ..*providers };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ pub enum TypingMode<I: Interner> {
|
|||
/// let x: <() as Assoc>::Output = true;
|
||||
/// }
|
||||
/// ```
|
||||
Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
|
||||
Analysis { defining_opaque_types: I::LocalDefIds, stalled_generators: I::LocalDefIds },
|
||||
/// The behavior during MIR borrowck is identical to `TypingMode::Analysis`
|
||||
/// except that the initial value for opaque types is the type computed during
|
||||
/// HIR typeck with unique unconstrained region inference variables.
|
||||
|
|
@ -73,13 +73,13 @@ pub enum TypingMode<I: Interner> {
|
|||
/// This is currently only used with by the new solver as it results in new
|
||||
/// non-universal defining uses of opaque types, which is a breaking change.
|
||||
/// See tests/ui/impl-trait/non-defining-use/as-projection-term.rs.
|
||||
Borrowck { defining_opaque_types: I::DefiningOpaqueTypes },
|
||||
Borrowck { defining_opaque_types: I::LocalDefIds },
|
||||
/// Any analysis after borrowck for a given body should be able to use all the
|
||||
/// hidden types defined by borrowck, without being able to define any new ones.
|
||||
///
|
||||
/// This is currently only used by the new solver, but should be implemented in
|
||||
/// the old solver as well.
|
||||
PostBorrowckAnalysis { defined_opaque_types: I::DefiningOpaqueTypes },
|
||||
PostBorrowckAnalysis { defined_opaque_types: I::LocalDefIds },
|
||||
/// After analysis, mostly during codegen and MIR optimizations, we're able to
|
||||
/// reveal all opaque types. As the concrete type should *never* be observable
|
||||
/// directly by the user, this should not be used by checks which may expose
|
||||
|
|
@ -94,13 +94,26 @@ pub enum TypingMode<I: Interner> {
|
|||
impl<I: Interner> TypingMode<I> {
|
||||
/// Analysis outside of a body does not define any opaque types.
|
||||
pub fn non_body_analysis() -> TypingMode<I> {
|
||||
TypingMode::Analysis { defining_opaque_types: Default::default() }
|
||||
TypingMode::Analysis {
|
||||
defining_opaque_types: Default::default(),
|
||||
stalled_generators: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn typeck_for_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
|
||||
TypingMode::Analysis {
|
||||
defining_opaque_types: cx.opaque_types_defined_by(body_def_id),
|
||||
stalled_generators: cx.stalled_generators_within(body_def_id),
|
||||
}
|
||||
}
|
||||
|
||||
/// While typechecking a body, we need to be able to define the opaque
|
||||
/// types defined by that body.
|
||||
pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
|
||||
TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
|
||||
TypingMode::Analysis {
|
||||
defining_opaque_types: cx.opaque_types_defined_by(body_def_id),
|
||||
stalled_generators: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ pub trait Interner:
|
|||
data: PredefinedOpaquesData<Self>,
|
||||
) -> Self::PredefinedOpaques;
|
||||
|
||||
type DefiningOpaqueTypes: Copy
|
||||
type LocalDefIds: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Default
|
||||
|
|
@ -330,10 +330,9 @@ pub trait Interner:
|
|||
binder: ty::Binder<Self, T>,
|
||||
) -> ty::Binder<Self, T>;
|
||||
|
||||
fn opaque_types_defined_by(
|
||||
self,
|
||||
defining_anchor: Self::LocalDefId,
|
||||
) -> Self::DefiningOpaqueTypes;
|
||||
fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds;
|
||||
|
||||
fn stalled_generators_within(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds;
|
||||
}
|
||||
|
||||
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue