Add an optional Span to BrAnon and use it to print better error for HRTB error from generator interior

This commit is contained in:
Jack Huey 2022-10-17 22:08:15 -04:00
parent 1e1e5b8d98
commit 00e314d5ed
23 changed files with 251 additions and 63 deletions

View File

@ -158,6 +158,7 @@ trait TypeOpInfo<'tcx> {
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
#[instrument(level = "debug", skip(self, mbcx))]
fn report_error(
&self,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
@ -167,6 +168,7 @@ trait TypeOpInfo<'tcx> {
) {
let tcx = mbcx.infcx.tcx;
let base_universe = self.base_universe();
debug!(?base_universe);
let Some(adjusted_universe) =
placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
@ -389,6 +391,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
)
}
#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
fn try_extract_error_from_region_constraints<'tcx>(
infcx: &InferCtxt<'tcx>,
placeholder_region: ty::Region<'tcx>,

View File

@ -355,7 +355,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
})
}
ty::BoundRegionKind::BrAnon(_) => None,
ty::BoundRegionKind::BrAnon(..) => None,
},
ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,

View File

@ -2976,7 +2976,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) {
for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br {
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
"an anonymous lifetime".to_string()
}
ty::BrNamed(_, name) => format!("lifetime `{}`", name),
@ -2984,7 +2984,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut err = generate_err(&br_name);
if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
// The only way for an anonymous lifetime to wind up
// in the return type but **also** be unconstrained is
// if it only appears in "associated types" in the

View File

@ -134,7 +134,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let name_str = intrinsic_name.as_str();
let bound_vars = tcx.mk_bound_variable_kinds(
[ty::BoundVariableKind::Region(ty::BrAnon(0)), ty::BoundVariableKind::Region(ty::BrEnv)]
[
ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
ty::BoundVariableKind::Region(ty::BrEnv),
]
.iter()
.copied(),
);
@ -142,7 +145,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
tcx.lang_items().va_list().map(|did| {
let region = tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) },
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) },
));
let env_region = tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
@ -364,7 +367,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
);
let discriminant_def_id = assoc_items[0];
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
(
1,
vec![
@ -418,7 +422,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
sym::raw_eq => {
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
let param_ty =
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
(1, vec![param_ty; 2], tcx.types.bool)

View File

@ -13,8 +13,9 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
use rustc_span::symbol::sym;
use rustc_span::Span;
@ -211,31 +212,52 @@ pub fn resolve_interior<'a, 'tcx>(
debug!("types in generator {:?}, span = {:?}", types, body.value.span);
let mut counter = 0;
// We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
// So, we need to actually do two passes: first by type to anonymize (preserving information
// required for diagnostics), then a second pass over all captured types to reassign disjoint
// region indices.
let mut captured_tys = FxHashSet::default();
let type_causes: Vec<_> = types
.into_iter()
.filter_map(|mut cause| {
// Erase regions and canonicalize late-bound regions to deduplicate as many types as we
// can.
let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
let erased = fcx.tcx.erase_regions(ty);
if captured_tys.insert(erased) {
// 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.
let folded = fcx.tcx.fold_regions(erased, |_, current_depth| {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(counter),
kind: ty::BrAnon(counter),
let mut counter = 0;
let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
let br = match region.kind() {
ty::ReVar(vid) => {
let origin = fcx.region_var_origin(vid);
match origin {
RegionVariableOrigin::EarlyBoundRegion(span, _) => {
let kind = ty::BrAnon(counter, Some(span));
let var = ty::BoundVar::from_u32(counter);
counter += 1;
ty::BoundRegion { var, kind }
}
_ => {
let kind = ty::BrAnon(counter, None);
let var = ty::BoundVar::from_u32(counter);
counter += 1;
ty::BoundRegion { var, kind }
}
}
}
_ => {
let kind = ty::BrAnon(counter, None);
let var = ty::BoundVar::from_u32(counter);
counter += 1;
ty::BoundRegion { var, kind }
}
};
let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
counter += 1;
r
});
cause.ty = folded;
if captured_tys.insert(ty) {
cause.ty = ty;
Some(cause)
} else {
None
@ -243,11 +265,29 @@ pub fn resolve_interior<'a, 'tcx>(
})
.collect();
let mut bound_vars: Vec<BoundVariableKind> = vec![];
let mut counter = 0;
let type_causes = fcx.tcx.fold_regions(type_causes, |region, current_depth| {
let br = match region.kind() {
ty::ReLateBound(_, br) => {
let kind = match br.kind {
ty::BrAnon(_, span) => ty::BrAnon(counter, span),
_ => br.kind,
};
let var = ty::BoundVar::from_usize(bound_vars.len());
bound_vars.push(ty::BoundVariableKind::Region(kind));
counter += 1;
ty::BoundRegion { var, kind }
}
_ => bug!("All regions should have been replaced by ReLateBound"),
};
let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
r
});
// Extract type components to build the witness type.
let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
let bound_vars = fcx.tcx.mk_bound_variable_kinds(
(0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
);
let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
let witness =
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));

View File

@ -209,6 +209,7 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
typeck_with_fallback(tcx, def_id, fallback)
}
#[instrument(level = "debug", skip(tcx, fallback), ret)]
fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,

View File

@ -89,10 +89,13 @@ impl<'a> DescriptionCtx<'a> {
};
me.span = Some(sp);
}
ty::BrAnon(idx) => {
ty::BrAnon(idx, span) => {
me.kind = "anon_num_here";
me.num_arg = idx+1;
me.span = Some(tcx.def_span(scope));
me.span = match span {
Some(_) => span,
None => Some(tcx.def_span(scope)),
}
},
_ => {
me.kind = "defined_here_reg";

View File

@ -738,7 +738,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
let var = self.canonical_var(info, r.into());
let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32()) };
let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
let region = ty::ReLateBound(self.binder_index, br);
self.tcx().mk_region(region)
}

View File

@ -206,9 +206,12 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
};
(text, sp)
}
ty::BrAnon(idx) => (
ty::BrAnon(idx, span) => (
format!("the anonymous lifetime #{} defined here", idx + 1),
tcx.def_span(scope)
match span {
Some(span) => span,
None => tcx.def_span(scope)
}
),
_ => (
format!("the lifetime `{}` as defined here", region),

View File

@ -10,6 +10,7 @@ pub mod find_anon_type;
mod mismatched_static_lifetime;
mod named_anon_conflict;
mod placeholder_error;
mod placeholder_relation;
mod static_impl_trait;
mod trait_impl_difference;
mod util;
@ -52,7 +53,9 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
// Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
// the nice region errors are required when running under the MIR borrow checker.
self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
self.try_report_named_anon_conflict()
.or_else(|| self.try_report_placeholder_conflict())
.or_else(|| self.try_report_placeholder_relation())
}
pub fn try_report(&self) -> Option<ErrorGuaranteed> {

View File

@ -68,7 +68,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let is_impl_item = region_info.is_impl_item;
match br {
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) => {}
_ => {
/* not an anonymous region */
debug!("try_report_named_anon_conflict: not an anonymous region");

View File

@ -0,0 +1,78 @@
use crate::infer::{
error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
};
use rustc_data_structures::intern::Interned;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty::{self, RePlaceholder, Region};
impl<'tcx> NiceRegionError<'_, 'tcx> {
/// Emitted wwhen given a `ConcreteFailure` when relating two placeholders.
pub(super) fn try_report_placeholder_relation(
&self,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
match &self.error {
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::RelateRegionParamBound(span),
Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
)) => {
let msg = "lifetime bound not satisfied";
let mut err = self.tcx().sess.struct_span_err(*span, msg);
let (sub_span, sub_symbol) = match sub_name {
ty::BrNamed(def_id, symbol) => {
(Some(self.tcx().def_span(def_id)), Some(symbol))
}
ty::BrAnon(_, span) => (*span, None),
ty::BrEnv => (None, None),
};
let (sup_span, sup_symbol) = match sup_name {
ty::BrNamed(def_id, symbol) => {
(Some(self.tcx().def_span(def_id)), Some(symbol))
}
ty::BrAnon(_, span) => (*span, None),
ty::BrEnv => (None, None),
};
match (sub_span, sup_span, sub_symbol, sup_symbol) {
(Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
err.span_note(
sub_span,
format!("the lifetime `{sub_symbol}` defined here..."),
);
err.span_note(
sup_span,
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
);
}
(Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
err.span_note(sub_span, format!("the lifetime defined here..."));
err.span_note(
sup_span,
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
);
}
(Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
err.span_note(
sub_span,
format!("the lifetime `{sub_symbol}` defined here..."),
);
err.span_note(
sup_span,
format!("...must outlive the lifetime defined here"),
);
}
(Some(sub_span), Some(sup_span), _, _) => {
err.span_note(sub_span, format!("the lifetime defined here, ..."));
err.span_note(
sup_span,
format!("...must outlive the lifetime defined here"),
);
}
_ => {}
}
Some(err)
}
_ => None,
}
}
}

View File

@ -336,8 +336,10 @@ impl<'tcx> CanonicalVarValues<'tcx> {
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
}
GenericArgKind::Lifetime(..) => {
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) };
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(i),
kind: ty::BrAnon(i, None),
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
GenericArgKind::Const(ct) => tcx

View File

@ -598,7 +598,7 @@ impl<'tcx> TyCtxt<'tcx> {
.replace_late_bound_regions(sig, |_| {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(counter),
kind: ty::BrAnon(counter),
kind: ty::BrAnon(counter, None),
};
let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
counter += 1;
@ -606,7 +606,7 @@ impl<'tcx> TyCtxt<'tcx> {
})
.0;
let bound_vars = self.mk_bound_variable_kinds(
(0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
(0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
);
Binder::bind_with_vars(inner, bound_vars)
}
@ -626,7 +626,9 @@ impl<'tcx> TyCtxt<'tcx> {
let index = entry.index();
let var = ty::BoundVar::from_usize(index);
let kind = entry
.or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(index as u32)))
.or_insert_with(|| {
ty::BoundVariableKind::Region(ty::BrAnon(index as u32, None))
})
.expect_region();
let br = ty::BoundRegion { var, kind };
self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))

View File

@ -2115,7 +2115,7 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
// If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound
match kind {
ty::BrAnon(_) | ty::BrEnv => r,
ty::BrAnon(..) | ty::BrEnv => r,
_ => {
// Index doesn't matter, since this is just for naming and these never get bound
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
@ -2226,10 +2226,10 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
let ty::BoundVariableKind::Region(var) = var else {
// This doesn't really matter because it doesn't get used,
// it's just an empty value
return ty::BrAnon(0);
return ty::BrAnon(0, None);
};
match var {
ty::BrAnon(_) | ty::BrEnv => {
ty::BrAnon(..) | ty::BrEnv => {
start_or_continue(&mut self, "for<", ", ");
let name = next_name(&self);
debug!(?name);
@ -2271,7 +2271,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
binder_level_idx: ty::DebruijnIndex,
br: ty::BoundRegion| {
let (name, kind) = match br.kind {
ty::BrAnon(_) | ty::BrEnv => {
ty::BrAnon(..) | ty::BrEnv => {
let name = next_name(&self);
if let Some(lt_idx) = lifetime_idx {

View File

@ -68,7 +68,7 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
impl fmt::Debug for ty::BoundRegionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
ty::BrAnon(n, span) => write!(f, "BrAnon({n:?}, {span:?})"),
ty::BrNamed(did, name) => {
if did.is_crate_root() {
write!(f, "BrNamed({})", name)

View File

@ -59,7 +59,7 @@ pub struct FreeRegion {
#[derive(HashStable)]
pub enum BoundRegionKind {
/// An anonymous region parameter for a given fn (&T)
BrAnon(u32),
BrAnon(u32, Option<Span>),
/// Named region parameters for functions (a in &'a T)
///

View File

@ -218,7 +218,7 @@ impl<'tcx> SymbolMangler<'tcx> {
let lifetimes = regions
.into_iter()
.map(|br| match br {
ty::BrAnon(i) => i,
ty::BrAnon(i, _) => i,
_ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
})
.max()
@ -335,7 +335,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
// Late-bound lifetimes use indices starting at 1,
// see `BinderLevel` for more details.
ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => {
ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i, _), .. }) => {
let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
let depth = binder.lifetime_depths.start + i;

View File

@ -1975,6 +1975,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
/// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
/// ```
#[instrument(level = "debug", skip(self), ret)]
fn constituent_types_for_ty(
&self,
t: ty::Binder<'tcx, Ty<'tcx>>,

View File

@ -728,7 +728,7 @@ fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx
ty::GenericParamDefKind::Lifetime => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_usize(substs.len()),
kind: ty::BrAnon(substs.len() as u32),
kind: ty::BrAnon(substs.len() as u32, None),
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}

View File

@ -498,13 +498,13 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t
ty::DebruijnIndex::from_u32(var.debruijn.depth()),
ty::BoundRegion {
var: ty::BoundVar::from_usize(var.index),
kind: ty::BrAnon(var.index as u32),
kind: ty::BrAnon(var.index as u32, None),
},
),
chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(),
chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder {
universe: ty::UniverseIndex::from_usize(p.ui.counter),
name: ty::BoundRegionKind::BrAnon(p.idx as u32),
name: ty::BoundRegionKind::BrAnon(p.idx as u32, None),
}),
chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static,
chalk_ir::LifetimeData::Empty(_) => {
@ -933,7 +933,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
}
}
ty::BoundRegionKind::BrAnon(var) => match self.parameters.entry(var) {
ty::BoundRegionKind::BrAnon(var, _) => match self.parameters.entry(var) {
Entry::Vacant(entry) => {
entry.insert(chalk_ir::VariableKind::Lifetime);
}
@ -991,13 +991,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> {
ty::ReLateBound(index, br) if index == self.binder_index => match br.kind {
ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
Some(idx) => {
let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx, None) };
return self.tcx.mk_region(ty::ReLateBound(index, new_br));
}
None => panic!("Missing `BrNamed`."),
},
ty::BrEnv => unimplemented!(),
ty::BrAnon(_) => {}
ty::BrAnon(..) => {}
},
_ => (),
};
@ -1072,14 +1072,16 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
Some(idx) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(*idx),
kind: ty::BrAnon(*idx),
kind: ty::BrAnon(*idx, None),
};
self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
}
None => {
let idx = self.named_regions.len() as u32;
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(idx),
kind: ty::BrAnon(idx, None),
};
self.named_regions.insert(_re.def_id, idx);
self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
}
@ -1156,7 +1158,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
match *r {
ty::RePlaceholder(p) if p.universe == self.universe_index => {
if let ty::BoundRegionKind::BrAnon(anon) = p.name {
if let ty::BoundRegionKind::BrAnon(anon, _) = p.name {
self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon);
}
}

View File

@ -0,0 +1,22 @@
// check-fail
// known-bug
// edition: 2021
// We really should accept this, but we need implied bounds between the regions
// in a generator interior.
pub trait FutureIterator {
type Future<'s, 'cx>: Send
where
's: 'cx;
}
fn call_2<I: FutureIterator>() -> impl Send {
async { // a generator checked for autotrait impl `Send`
//~^ lifetime bound not satisfied
let x = None::<I::Future<'_, '_>>; // a type referencing GAT
async {}.await; // a yield point
}
}
fn main() {}

View File

@ -0,0 +1,23 @@
error: lifetime bound not satisfied
--> $DIR/issue-100013.rs:15:5
|
LL | / async { // a generator checked for autotrait impl `Send`
LL | |
LL | | let x = None::<I::Future<'_, '_>>; // a type referencing GAT
LL | | async {}.await; // a yield point
LL | | }
| |_____^
|
note: the lifetime defined here, ...
--> $DIR/issue-100013.rs:17:38
|
LL | let x = None::<I::Future<'_, '_>>; // a type referencing GAT
| ^^
note: ...must outlive the lifetime defined here
--> $DIR/issue-100013.rs:17:34
|
LL | let x = None::<I::Future<'_, '_>>; // a type referencing GAT
| ^^
error: aborting due to previous error