Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,7 @@ rustc_queries! {
}

query coroutine_hidden_types(
def_id: DefId
def_id: DefId,
) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
desc { "looking up the hidden types stored across await points in a coroutine" }
}
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3112,6 +3112,17 @@ impl<'tcx> TyCtxt<'tcx> {
T::collect_and_apply(iter, |xs| self.mk_bound_variable_kinds(xs))
}

pub fn mk_outlives_from_iter<I, T>(self, iter: I) -> T::Output
where
I: Iterator<Item = T>,
T: CollectAndApply<
ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
&'tcx ty::List<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
>,
{
T::collect_and_apply(iter, |xs| self.mk_outlives(xs))
}

/// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`,
/// typically generated by `#[derive(LintDiagnostic)]`).
#[track_caller]
Expand Down
57 changes: 55 additions & 2 deletions compiler/rustc_traits/src/coroutine_witnesses.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, TyCtxt, fold_regions};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions};
use rustc_trait_selection::traits::{ObligationCtxt, with_replaced_escaping_bound_vars};

/// Return the set of types that should be taken into account when checking
/// trait bounds on a coroutine's internal state. This properly replaces
Expand Down Expand Up @@ -29,8 +34,56 @@ pub(crate) fn coroutine_hidden_types<'tcx>(
ty
}),
);

let assumptions = compute_assumptions(tcx, def_id, bound_tys);

ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
ty::CoroutineWitnessTypes { types: bound_tys, assumptions: ty::List::empty() },
ty::CoroutineWitnessTypes { types: bound_tys, assumptions },
tcx.mk_bound_variable_kinds(&vars),
))
}

fn compute_assumptions<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
bound_tys: &'tcx ty::List<Ty<'tcx>>,
) -> &'tcx ty::List<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> {
let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis {
defining_opaque_types_and_generators: ty::List::empty(),
});
with_replaced_escaping_bound_vars(&infcx, &mut vec![None], bound_tys, |bound_tys| {
let param_env = tcx.param_env(def_id);
let ocx = ObligationCtxt::new(&infcx);

ocx.register_obligations(bound_tys.iter().map(|ty| {
Obligation::new(
tcx,
ObligationCause::dummy(),
param_env,
ty::ClauseKind::WellFormed(ty.into()),
)
}));
let _errors = ocx.select_all_or_error();

let region_obligations = infcx.take_registered_region_obligations();
let region_constraints = infcx.take_and_reset_region_constraints();

let outlives = make_query_region_constraints(
tcx,
region_obligations,
&region_constraints,
)
.outlives
.fold_with(&mut OpportunisticRegionResolver::new(&infcx));

tcx.mk_outlives_from_iter(
outlives
.into_iter()
.map(|(o, _)| o)
// FIXME(higher_ranked_auto): We probably should deeply resolve these before
// filtering out infers which only correspond to unconstrained infer regions
// which we can sometimes get.
.filter(|o| !o.has_infer()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is that all regions in bound_tys have been replaced with bound regions that were then substituted with (I presume) placeholders... I'm wondering though--- so I guess the assumption is that outlives in here will only be between placeholders? It seems plausible we could wind up also with ty::Param, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g., where T: 'a and an obligation to prove T: !a could be done if 'a: !a:... I guess that still involves at least one placeholder. Proabbly we never wind up with T: 'a as a requirement right now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not, but I would be surprised if that's unsound, since we'd already be on the hook to prove a similar obligation when checking the coroutine itself.

)
})
}