Auto merge of #103171 - jackh726:gen-interior-hrtb-error, r=cjgillot

Better error for HRTB error from generator interior

cc #100013

This is just a first pass at an error. It could be better, and shouldn't really be emitted in the first place. But this is better than what was being emitted before.
This commit is contained in:
bors 2022-11-09 02:02:28 +00:00
commit bc2504a83c
23 changed files with 344 additions and 63 deletions

View File

@ -158,6 +158,7 @@ trait TypeOpInfo<'tcx> {
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>; ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
#[instrument(level = "debug", skip(self, mbcx))]
fn report_error( fn report_error(
&self, &self,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
@ -167,6 +168,7 @@ trait TypeOpInfo<'tcx> {
) { ) {
let tcx = mbcx.infcx.tcx; let tcx = mbcx.infcx.tcx;
let base_universe = self.base_universe(); let base_universe = self.base_universe();
debug!(?base_universe);
let Some(adjusted_universe) = let Some(adjusted_universe) =
placeholder.universe.as_u32().checked_sub(base_universe.as_u32()) 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>( fn try_extract_error_from_region_constraints<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
placeholder_region: ty::Region<'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, ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,

View File

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

View File

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

View File

@ -13,10 +13,13 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet; use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; 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::middle::region::{self, Scope, ScopeData, YieldData};
use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable}; use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use smallvec::{smallvec, SmallVec};
mod drop_ranges; mod drop_ranges;
@ -211,31 +214,57 @@ pub fn resolve_interior<'a, 'tcx>(
debug!("types in generator {:?}, span = {:?}", types, body.value.span); 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 mut captured_tys = FxHashSet::default();
let type_causes: Vec<_> = types let type_causes: Vec<_> = types
.into_iter() .into_iter()
.filter_map(|mut cause| { .filter_map(|mut cause| {
// Erase regions and canonicalize late-bound regions to deduplicate as many types as we // Replace all regions inside the generator interior with late bound regions.
// can. // Note that each region slot in the types gets a new fresh late bound region,
let ty = fcx.normalize_associated_types_in(cause.span, cause.ty); // which means that none of the regions inside relate to any other, even if
let erased = fcx.tcx.erase_regions(ty); // typeck had previously found constraints that would cause them to be related.
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 r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
counter += 1;
r
});
cause.ty = folded; let mut counter = 0;
let mut mk_bound_region = |span| {
let kind = ty::BrAnon(counter, span);
let var = ty::BoundVar::from_u32(counter);
counter += 1;
ty::BoundRegion { var, kind }
};
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, _) => {
mk_bound_region(Some(span))
}
_ => mk_bound_region(None),
}
}
// FIXME: these should use `BrNamed`
ty::ReEarlyBound(region) => {
mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
}
ty::ReLateBound(_, ty::BoundRegion { kind, .. })
| ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span),
ty::BoundRegionKind::BrNamed(def_id, _) => {
mk_bound_region(Some(fcx.tcx.def_span(def_id)))
}
ty::BoundRegionKind::BrEnv => mk_bound_region(None),
},
_ => mk_bound_region(None),
};
let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
r
});
if captured_tys.insert(ty) {
cause.ty = ty;
Some(cause) Some(cause)
} else { } else {
None None
@ -243,11 +272,38 @@ pub fn resolve_interior<'a, 'tcx>(
}) })
.collect(); .collect();
let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
let mut counter = 0;
// Optimization: If there is only one captured type, then we don't actually
// need to fold and reindex (since the first type doesn't change).
let type_causes = if captured_tys.len() > 0 {
// Optimization: Use `replace_escaping_bound_vars_uncached` instead of
// `fold_regions`, since we only have late bound regions, and it skips
// types without bound regions.
fcx.tcx.replace_escaping_bound_vars_uncached(
type_causes,
FnMutDelegate {
regions: &mut |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;
fcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var, kind }))
},
types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
},
)
} else {
type_causes
};
// Extract type components to build the witness type. // Extract type components to build the witness type.
let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty)); let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
let bound_vars = fcx.tcx.mk_bound_variable_kinds( let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
(0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
);
let witness = let witness =
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone())); 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) typeck_with_fallback(tcx, def_id, fallback)
} }
#[instrument(level = "debug", skip(tcx, fallback), ret)]
fn typeck_with_fallback<'tcx>( fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId, def_id: LocalDefId,

View File

@ -89,10 +89,13 @@ impl<'a> DescriptionCtx<'a> {
}; };
me.span = Some(sp); me.span = Some(sp);
} }
ty::BrAnon(idx) => { ty::BrAnon(idx, span) => {
me.kind = "anon_num_here"; me.kind = "anon_num_here";
me.num_arg = idx+1; 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"; me.kind = "defined_here_reg";

View File

@ -738,7 +738,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
r: ty::Region<'tcx>, r: ty::Region<'tcx>,
) -> ty::Region<'tcx> { ) -> ty::Region<'tcx> {
let var = self.canonical_var(info, r.into()); 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); let region = ty::ReLateBound(self.binder_index, br);
self.tcx().mk_region(region) self.tcx().mk_region(region)
} }

View File

@ -207,9 +207,12 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
}; };
(text, sp) (text, sp)
} }
ty::BrAnon(idx) => ( ty::BrAnon(idx, span) => (
format!("the anonymous lifetime #{} defined here", idx + 1), 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), format!("the lifetime `{}` as defined here", region),

View File

@ -10,6 +10,7 @@ pub mod find_anon_type;
mod mismatched_static_lifetime; mod mismatched_static_lifetime;
mod named_anon_conflict; mod named_anon_conflict;
mod placeholder_error; mod placeholder_error;
mod placeholder_relation;
mod static_impl_trait; mod static_impl_trait;
mod trait_impl_difference; mod trait_impl_difference;
mod util; mod util;
@ -52,7 +53,9 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { 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 // 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. // 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> { 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; let is_impl_item = region_info.is_impl_item;
match br { match br {
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {} ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) => {}
_ => { _ => {
/* not an anonymous region */ /* not an anonymous region */
debug!("try_report_named_anon_conflict: not an anonymous region"); debug!("try_report_named_anon_conflict: not an anonymous region");

View File

@ -0,0 +1,79 @@
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"),
);
}
_ => {}
}
err.note("this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)");
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() tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
} }
GenericArgKind::Lifetime(..) => { GenericArgKind::Lifetime(..) => {
let br = let br = ty::BoundRegion {
ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) }; var: ty::BoundVar::from_u32(i),
kind: ty::BrAnon(i, None),
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
} }
GenericArgKind::Const(ct) => tcx GenericArgKind::Const(ct) => tcx

View File

@ -598,7 +598,7 @@ impl<'tcx> TyCtxt<'tcx> {
.replace_late_bound_regions(sig, |_| { .replace_late_bound_regions(sig, |_| {
let br = ty::BoundRegion { let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(counter), 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)); let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
counter += 1; counter += 1;
@ -606,7 +606,7 @@ impl<'tcx> TyCtxt<'tcx> {
}) })
.0; .0;
let bound_vars = self.mk_bound_variable_kinds( 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) Binder::bind_with_vars(inner, bound_vars)
} }
@ -626,7 +626,9 @@ impl<'tcx> TyCtxt<'tcx> {
let index = entry.index(); let index = entry.index();
let var = ty::BoundVar::from_usize(index); let var = ty::BoundVar::from_usize(index);
let kind = entry 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(); .expect_region();
let br = ty::BoundRegion { var, kind }; let br = ty::BoundRegion { var, kind };
self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)) 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 // If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound // async fns, we get a `for<'r> Send` bound
match kind { 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 // 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 }; 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 { let ty::BoundVariableKind::Region(var) = var else {
// This doesn't really matter because it doesn't get used, // This doesn't really matter because it doesn't get used,
// it's just an empty value // it's just an empty value
return ty::BrAnon(0); return ty::BrAnon(0, None);
}; };
match var { match var {
ty::BrAnon(_) | ty::BrEnv => { ty::BrAnon(..) | ty::BrEnv => {
start_or_continue(&mut self, "for<", ", "); start_or_continue(&mut self, "for<", ", ");
let name = next_name(&self); let name = next_name(&self);
debug!(?name); debug!(?name);
@ -2271,7 +2271,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
binder_level_idx: ty::DebruijnIndex, binder_level_idx: ty::DebruijnIndex,
br: ty::BoundRegion| { br: ty::BoundRegion| {
let (name, kind) = match br.kind { let (name, kind) = match br.kind {
ty::BrAnon(_) | ty::BrEnv => { ty::BrAnon(..) | ty::BrEnv => {
let name = next_name(&self); let name = next_name(&self);
if let Some(lt_idx) = lifetime_idx { 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 { impl fmt::Debug for ty::BoundRegionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match *self {
ty::BrAnon(n) => write!(f, "BrAnon({:?})", n), ty::BrAnon(n, span) => write!(f, "BrAnon({n:?}, {span:?})"),
ty::BrNamed(did, name) => { ty::BrNamed(did, name) => {
if did.is_crate_root() { if did.is_crate_root() {
write!(f, "BrNamed({})", name) write!(f, "BrNamed({})", name)

View File

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

View File

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

View File

@ -1971,6 +1971,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32] /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
/// Zed<i32> where enum Zed { A(T), B(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( fn constituent_types_for_ty(
&self, &self,
t: ty::Binder<'tcx, Ty<'tcx>>, 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 => { ty::GenericParamDefKind::Lifetime => {
let br = ty::BoundRegion { let br = ty::BoundRegion {
var: ty::BoundVar::from_usize(substs.len()), 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() 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::DebruijnIndex::from_u32(var.debruijn.depth()),
ty::BoundRegion { ty::BoundRegion {
var: ty::BoundVar::from_usize(var.index), 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::InferenceVar(_var) => unimplemented!(),
chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder { chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder {
universe: ty::UniverseIndex::from_usize(p.ui.counter), 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::Static => return interner.tcx.lifetimes.re_static,
chalk_ir::LifetimeData::Empty(_) => { 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::Vacant(entry) => {
entry.insert(chalk_ir::VariableKind::Lifetime); 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::ReLateBound(index, br) if index == self.binder_index => match br.kind {
ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
Some(idx) => { 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)); return self.tcx.mk_region(ty::ReLateBound(index, new_br));
} }
None => panic!("Missing `BrNamed`."), None => panic!("Missing `BrNamed`."),
}, },
ty::BrEnv => unimplemented!(), ty::BrEnv => unimplemented!(),
ty::BrAnon(_) => {} ty::BrAnon(..) => {}
}, },
_ => (), _ => (),
}; };
@ -1072,14 +1072,16 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
Some(idx) => { Some(idx) => {
let br = ty::BoundRegion { let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(*idx), 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)) self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
} }
None => { None => {
let idx = self.named_regions.len() as u32; let idx = self.named_regions.len() as u32;
let br = let br = ty::BoundRegion {
ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) }; var: ty::BoundVar::from_u32(idx),
kind: ty::BrAnon(idx, None),
};
self.named_regions.insert(_re.def_id, idx); self.named_regions.insert(_re.def_id, idx);
self.tcx.mk_region(ty::ReLateBound(self.binder_index, br)) 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> { fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
match *r { match *r {
ty::RePlaceholder(p) if p.universe == self.universe_index => { 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); self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon);
} }
} }

View File

@ -0,0 +1,39 @@
// 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<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 call2<'a, 'b, I: FutureIterator>() -> impl Send {
async { // a generator checked for autotrait impl `Send`
//~^ lifetime bound not satisfied
let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
//~^ lifetime may not live long enough
async {}.await; // a yield point
}
}
fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
async { // a generator checked for autotrait impl `Send`
//~^ lifetime bound not satisfied
let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
async {}.await; // a yield point
}
}
fn main() {}

View File

@ -0,0 +1,82 @@
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
| ^^
= note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
error: lifetime bound not satisfied
--> $DIR/issue-100013.rs:23:5
|
LL | / async { // a generator checked for autotrait impl `Send`
LL | |
LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
LL | |
LL | | async {}.await; // a yield point
LL | | }
| |_____^
|
note: the lifetime defined here...
--> $DIR/issue-100013.rs:22:14
|
LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
| ^^
note: ...must outlive the lifetime defined here
--> $DIR/issue-100013.rs:22:10
|
LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
| ^^
= note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
error: lifetime may not live long enough
--> $DIR/issue-100013.rs:25:17
|
LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
| ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
error: lifetime bound not satisfied
--> $DIR/issue-100013.rs:32:5
|
LL | / async { // a generator checked for autotrait impl `Send`
LL | |
LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
LL | | async {}.await; // a yield point
LL | | }
| |_____^
|
note: the lifetime defined here...
--> $DIR/issue-100013.rs:31:18
|
LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
| ^^
note: ...must outlive the lifetime defined here
--> $DIR/issue-100013.rs:31:10
|
LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
| ^^
= note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
error: aborting due to 4 previous errors