1
Fork 0

Compute generator saved locals on MIR.

This commit is contained in:
Camille GILLOT 2022-10-01 15:57:22 +02:00
parent 400cb9aa41
commit 60e04d1e8c
18 changed files with 392 additions and 19 deletions

View file

@ -139,4 +139,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.clone()
}
fn drain_unstalled_obligations(
&mut self,
_: &InferCtxt<'tcx>,
) -> Vec<PredicateObligation<'tcx>> {
unimplemented!()
}
}

View file

@ -135,6 +135,13 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
errors
}
fn drain_unstalled_obligations(
&mut self,
_: &InferCtxt<'tcx>,
) -> Vec<PredicateObligation<'tcx>> {
unimplemented!()
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.iter().cloned().collect()
}

View file

@ -2226,7 +2226,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
match *ty.kind() {
ty::Generator(did, ..) => {
ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, _) => {
generator = generator.or(Some(did));
outer_generator = Some(did);
}
@ -2256,7 +2256,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
match *ty.kind() {
ty::Generator(did, ..) => {
ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, ..) => {
generator = generator.or(Some(did));
outer_generator = Some(did);
}
@ -2345,6 +2345,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => return false,
};
let generator_within_in_progress_typeck = match &self.typeck_results {
Some(t) => t.hir_owner.to_def_id() == generator_did_root,
_ => false,
};
let mut interior_or_upvar_span = None;
let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
@ -2364,6 +2369,35 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
*span,
Some((*scope_span, *yield_span, *expr, from_awaited_ty)),
));
if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span, None));
}
} else if self.tcx.sess.opts.unstable_opts.drop_tracking_mir
// Avoid disclosing internal information to downstream crates.
&& generator_did.is_local()
// Try to avoid cycles.
&& !generator_within_in_progress_typeck
{
let generator_info = &self.tcx.mir_generator_witnesses(generator_did);
debug!(?generator_info);
'find_source: for (variant, source_info) in
generator_info.variant_fields.iter().zip(&generator_info.variant_source_info)
{
debug!(?variant);
for &local in variant {
let decl = &generator_info.field_tys[local];
debug!(?decl);
if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.is_static_ptr {
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(
decl.source_info.span,
Some((None, source_info.span, None, from_awaited_ty)),
));
break 'find_source;
}
}
}
}
if interior_or_upvar_span.is_none() {
@ -3012,6 +3046,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
err.note(msg.trim_end_matches(", "))
}
ty::GeneratorWitnessMIR(def_id, substs) => {
use std::fmt::Write;
// FIXME: this is kind of an unusual format for rustc, can we make it more clear?
// Maybe we should just remove this note altogether?
// FIXME: only print types which don't meet the trait requirement
let mut msg =
"required because it captures the following types: ".to_owned();
for bty in tcx.generator_hidden_types(*def_id) {
let ty = bty.subst(tcx, substs);
write!(msg, "`{}`, ", ty).unwrap();
}
err.note(msg.trim_end_matches(", "))
}
ty::Generator(def_id, _, _) => {
let sp = self.tcx.def_span(def_id);

View file

@ -141,6 +141,55 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.select(selcx)
}
fn drain_unstalled_obligations(
&mut self,
infcx: &InferCtxt<'tcx>,
) -> Vec<PredicateObligation<'tcx>> {
let mut processor = DrainProcessor { removed_predicates: Vec::new(), infcx };
let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor);
assert!(outcome.errors.is_empty());
return processor.removed_predicates;
struct DrainProcessor<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
removed_predicates: Vec<PredicateObligation<'tcx>>,
}
impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> {
type Obligation = PendingPredicateObligation<'tcx>;
type Error = !;
type OUT = Outcome<Self::Obligation, Self::Error>;
fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
pending_obligation
.stalled_on
.iter()
.any(|&var| self.infcx.ty_or_const_infer_var_changed(var))
}
fn process_obligation(
&mut self,
pending_obligation: &mut PendingPredicateObligation<'tcx>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, !> {
assert!(self.needs_process_obligation(pending_obligation));
self.removed_predicates.push(pending_obligation.obligation.clone());
ProcessResult::Changed(vec![])
}
fn process_backedge<'c, I>(
&mut self,
cycle: I,
_marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
) -> Result<(), !>
where
I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
{
self.removed_predicates.extend(cycle.map(|c| c.obligation.clone()));
Ok(())
}
}
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.predicates.map_pending_obligations(|o| o.obligation.clone())
}

View file

@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_middle::ty::{
self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt,
ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitable,
};
use rustc_session::config::TraitSolver;
use rustc_span::def_id::DefId;
@ -1285,8 +1285,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::GeneratorWitness(tys) => {
stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
}
ty::GeneratorWitnessMIR(..) => {
todo!()
ty::GeneratorWitnessMIR(def_id, substs) => {
let tcx = self.tcx();
stack.extend(tcx.generator_hidden_types(def_id).map(|bty| {
let ty = bty.subst(tcx, substs);
debug_assert!(!ty.has_late_bound_regions());
ty
}))
}
// If we have a projection type, make sure to normalize it so we replace it

View file

@ -2183,8 +2183,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars))
}
ty::GeneratorWitnessMIR(..) => {
todo!()
ty::GeneratorWitnessMIR(def_id, ref substs) => {
let hidden_types = bind_generator_hidden_types_above(
self.infcx,
def_id,
substs,
obligation.predicate.bound_vars(),
);
Where(hidden_types)
}
ty::Closure(_, substs) => {
@ -2284,8 +2290,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
types.map_bound(|types| types.to_vec())
}
ty::GeneratorWitnessMIR(..) => {
todo!()
ty::GeneratorWitnessMIR(def_id, ref substs) => {
bind_generator_hidden_types_above(self.infcx, def_id, substs, t.bound_vars())
}
// For `PhantomData<T>`, we pass `T`.
@ -2930,3 +2936,56 @@ pub enum ProjectionMatchesProjection {
Ambiguous,
No,
}
/// Replace all regions inside the generator interior with late bound regions.
/// Note that each region slot in the types gets a new fresh late bound region, which means that
/// none of the regions inside relate to any other, even if typeck had previously found constraints
/// that would cause them to be related.
#[instrument(level = "trace", skip(infcx), ret)]
fn bind_generator_hidden_types_above<'tcx>(
infcx: &InferCtxt<'tcx>,
def_id: DefId,
substs: ty::SubstsRef<'tcx>,
bound_vars: &ty::List<ty::BoundVariableKind>,
) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
let tcx = infcx.tcx;
let mut seen_tys = FxHashSet::default();
let considering_regions = infcx.considering_regions;
let num_bound_variables = bound_vars.len() as u32;
let mut counter = num_bound_variables;
let hidden_types: Vec<_> = tcx
.generator_hidden_types(def_id)
// Deduplicate tys to avoid repeated work.
.filter(|bty| seen_tys.insert(*bty))
.map(|bty| {
let mut ty = bty.subst(tcx, substs);
// Only remap erased regions if we use them.
if considering_regions {
ty = tcx.fold_regions(ty, |mut r, current_depth| {
if let ty::ReErased = r.kind() {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(counter),
kind: ty::BrAnon(counter, None),
};
counter += 1;
r = tcx.mk_region(ty::ReLateBound(current_depth, br));
}
r
})
}
ty
})
.collect();
if considering_regions {
debug_assert!(!hidden_types.has_erased_regions());
}
let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.iter().chain(
(num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
));
ty::Binder::bind_with_vars(hidden_types, bound_vars)
}