Auto merge of #101692 - cjgillot:generator-lazy-witness, r=oli-obk
Compute generator saved locals on MIR Generators are currently type-checked by introducing a `witness` type variable, which is unified with a `GeneratorWitness(captured types)` whose purpose is to ensure that the auto traits correctly migrate from the captured types to the `witness` type. This requires computing the captured types on HIR during type-checking, only to re-do it on MIR later. This PR proposes to drop the HIR-based computation, and only keep the MIR one. This is done in 3 steps. 1. During type-checking, the `witness` type variable is never unified. This allows to stall all the obligations that depend on it until the end of type-checking. Then, the stalled obligations are marked as successful, and saved into the typeck results for later verification. 2. At type-checking writeback, `witness` is replaced by `GeneratorWitnessMIR(def_id, substs)`. From this point on, all trait selection involving `GeneratorWitnessMIR` will fetch the MIR-computed locals, similar to what opaque types do. There is no lifetime to be preserved here: we consider all the lifetimes appearing in this witness type to be higher-ranked. 3. After borrowck, the stashed obligations are verified against the actually computed types, in the `check_generator_obligations` query. If any obligation was wrongly marked as fulfilled in step 1, it should be reported here. There are still many issues: - ~I am not too happy having to filter out some locals from the checked bounds, I think this is MIR building that introduces raw pointers polluting the analysis;~ solved by a check specific to static variables. - the diagnostics for captured types don't show where they are used/dropped; - I do not attempt to support chalk. cc `@eholk` `@jyn514` for the drop-tracking work r? `@oli-obk` as you warned me of potential unsoundness
This commit is contained in:
commit
6cd6bad51f
270 changed files with 6269 additions and 601 deletions
|
@ -331,6 +331,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(_)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Param(_)
|
||||
|
@ -382,6 +383,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(_)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Param(_)
|
||||
|
|
|
@ -40,12 +40,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
|||
self.obligations.push(obligation);
|
||||
}
|
||||
|
||||
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||
let errors = self.select_where_possible(infcx);
|
||||
if !errors.is_empty() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
|
||||
self.obligations
|
||||
.drain(..)
|
||||
.map(|obligation| FulfillmentError {
|
||||
|
@ -144,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!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -414,6 +414,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Never
|
||||
| ty::Foreign(..) => tcx.types.unit,
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
|||
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
|
||||
}
|
||||
|
||||
ty::GeneratorWitnessMIR(..) => todo!(),
|
||||
|
||||
// For `PhantomData<T>`, we pass `T`.
|
||||
ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
|
||||
|
||||
|
@ -88,6 +90,7 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
|||
| ty::Ref(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Array(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
|
@ -173,6 +176,8 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
|||
ty::GeneratorWitness(types) => {
|
||||
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
|
||||
}
|
||||
|
||||
ty::GeneratorWitnessMIR(..) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,6 +220,7 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
|||
| ty::Dynamic(_, _, _)
|
||||
| ty::Generator(_, _, _)
|
||||
| ty::GeneratorWitness(_)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Alias(_, _)
|
||||
|
|
|
@ -40,15 +40,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
|||
self.obligations.insert(obligation);
|
||||
}
|
||||
|
||||
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||
{
|
||||
let errors = self.select_where_possible(infcx);
|
||||
|
||||
if !errors.is_empty() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
|
||||
// any remaining obligations are errors
|
||||
self.obligations
|
||||
.iter()
|
||||
|
@ -143,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()
|
||||
}
|
||||
|
|
|
@ -696,7 +696,9 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
|
|||
// This should only be created when checking whether we have to check whether some
|
||||
// auto trait impl applies. There will never be multiple impls, so we can just
|
||||
// act as if it were a local type here.
|
||||
ty::GeneratorWitness(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
|
||||
ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(..) => {
|
||||
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
|
||||
}
|
||||
ty::Alias(ty::Opaque, ..) => {
|
||||
// This merits some explanation.
|
||||
// Normally, opaque types are not involved when performing
|
||||
|
|
|
@ -101,6 +101,18 @@ pub trait InferCtxtExt<'tcx> {
|
|||
}
|
||||
|
||||
pub trait TypeErrCtxtExt<'tcx> {
|
||||
fn build_overflow_error<T>(
|
||||
&self,
|
||||
predicate: &T,
|
||||
span: Span,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
|
||||
where
|
||||
T: fmt::Display
|
||||
+ TypeFoldable<'tcx>
|
||||
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
|
||||
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
|
||||
|
||||
fn report_overflow_error<T>(
|
||||
&self,
|
||||
predicate: &T,
|
||||
|
@ -478,6 +490,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
suggest_increasing_limit: bool,
|
||||
mutate: impl FnOnce(&mut Diagnostic),
|
||||
) -> !
|
||||
where
|
||||
T: fmt::Display
|
||||
+ TypeFoldable<'tcx>
|
||||
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
|
||||
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
|
||||
{
|
||||
let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit);
|
||||
mutate(&mut err);
|
||||
err.emit();
|
||||
|
||||
self.tcx.sess.abort_if_errors();
|
||||
bug!();
|
||||
}
|
||||
|
||||
fn build_overflow_error<T>(
|
||||
&self,
|
||||
predicate: &T,
|
||||
span: Span,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
|
||||
where
|
||||
T: fmt::Display
|
||||
+ TypeFoldable<'tcx>
|
||||
|
@ -511,11 +543,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
self.suggest_new_overflow_limit(&mut err);
|
||||
}
|
||||
|
||||
mutate(&mut err);
|
||||
|
||||
err.emit();
|
||||
self.tcx.sess.abort_if_errors();
|
||||
bug!();
|
||||
err
|
||||
}
|
||||
|
||||
/// Reports that an overflow has occurred and halts compilation. We
|
||||
|
@ -1891,6 +1919,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
ty::Generator(..) => Some(16),
|
||||
ty::Foreign(..) => Some(17),
|
||||
ty::GeneratorWitness(..) => Some(18),
|
||||
ty::GeneratorWitnessMIR(..) => Some(19),
|
||||
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.ignore_for_traits {
|
||||
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);
|
||||
|
||||
|
|
|
@ -132,14 +132,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
|||
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
|
||||
}
|
||||
|
||||
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||
{
|
||||
let errors = self.select_where_possible(infcx);
|
||||
if !errors.is_empty() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
|
||||
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
|
||||
}
|
||||
|
||||
|
@ -148,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())
|
||||
}
|
||||
|
|
|
@ -1605,6 +1605,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(..)
|
||||
// Integers and floats always have `u8` as their discriminant.
|
||||
|
@ -1654,6 +1655,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Never
|
||||
// Extern types have unit metadata, according to RFC 2850
|
||||
| ty::Foreign(_)
|
||||
|
|
|
@ -31,6 +31,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
| ty::FnPtr(_)
|
||||
| ty::Char
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::RawPtr(_)
|
||||
| ty::Ref(..)
|
||||
| ty::Str
|
||||
|
|
|
@ -216,12 +216,16 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
|||
let substs = substs.try_fold_with(self)?;
|
||||
let recursion_limit = self.tcx().recursion_limit();
|
||||
if !recursion_limit.value_within_limit(self.anon_depth) {
|
||||
self.infcx.err_ctxt().report_overflow_error(
|
||||
&ty,
|
||||
self.cause.span,
|
||||
true,
|
||||
|_| {},
|
||||
);
|
||||
// A closure or generator may have itself as in its upvars.
|
||||
// This should be checked handled by the recursion check for opaque
|
||||
// types, but we may end up here before that check can happen.
|
||||
// In that case, we delay a bug to mark the trip, and continue without
|
||||
// revealing the opaque.
|
||||
self.infcx
|
||||
.err_ctxt()
|
||||
.build_overflow_error(&ty, self.cause.span, true)
|
||||
.delay_as_bug();
|
||||
return ty.try_super_fold_with(self);
|
||||
}
|
||||
|
||||
let generic_ty = self.tcx().bound_type_of(def_id);
|
||||
|
|
|
@ -765,7 +765,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::Tuple(_)
|
||||
| ty::GeneratorWitness(_) => {
|
||||
| ty::GeneratorWitness(_)
|
||||
| ty::GeneratorWitnessMIR(..) => {
|
||||
// These are built-in, and cannot have a custom `impl const Destruct`.
|
||||
candidates.vec.push(ConstDestructCandidate(None));
|
||||
}
|
||||
|
@ -826,6 +827,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
| ty::Closure(_, _)
|
||||
| ty::Generator(_, _, _)
|
||||
| ty::GeneratorWitness(_)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Never
|
||||
| ty::Alias(..)
|
||||
| ty::Param(_)
|
||||
|
|
|
@ -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,6 +1285,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
ty::GeneratorWitness(tys) => {
|
||||
stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
|
||||
}
|
||||
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
|
||||
// with a fresh infer variable
|
||||
|
|
|
@ -2066,6 +2066,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
| ty::Ref(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Array(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
|
@ -2182,6 +2183,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars))
|
||||
}
|
||||
|
||||
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) => {
|
||||
// (*) binder moved here
|
||||
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
|
||||
|
@ -2279,6 +2290,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
types.map_bound(|types| types.to_vec())
|
||||
}
|
||||
|
||||
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`.
|
||||
ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()),
|
||||
|
||||
|
@ -2921,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)
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
|
|||
ty::Closure(..) => {
|
||||
return ControlFlow::Break(ty);
|
||||
}
|
||||
ty::Generator(..) | ty::GeneratorWitness(..) => {
|
||||
ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => {
|
||||
return ControlFlow::Break(ty);
|
||||
}
|
||||
ty::FnDef(..) => {
|
||||
|
|
|
@ -551,6 +551,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||
| ty::Error(_)
|
||||
| ty::Str
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Never
|
||||
| ty::Param(_)
|
||||
| ty::Bound(..)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue