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:
commit
bc2504a83c
@ -158,6 +158,7 @@ fn nice_error(
|
||||
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 @@ fn report_error(
|
||||
) {
|
||||
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>,
|
||||
|
@ -355,7 +355,7 @@ fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
|
||||
})
|
||||
}
|
||||
|
||||
ty::BoundRegionKind::BrAnon(_) => None,
|
||||
ty::BoundRegionKind::BrAnon(..) => None,
|
||||
},
|
||||
|
||||
ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
|
||||
|
@ -2980,7 +2980,7 @@ fn validate_late_bound_regions(
|
||||
) {
|
||||
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),
|
||||
@ -2988,7 +2988,7 @@ fn validate_late_bound_regions(
|
||||
|
||||
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
|
||||
|
@ -134,15 +134,18 @@ 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)]
|
||||
.iter()
|
||||
.copied(),
|
||||
[
|
||||
ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
|
||||
ty::BoundVariableKind::Region(ty::BrEnv),
|
||||
]
|
||||
.iter()
|
||||
.copied(),
|
||||
);
|
||||
let mk_va_list_ty = |mutbl| {
|
||||
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)
|
||||
|
@ -13,10 +13,13 @@
|
||||
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::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
mod drop_ranges;
|
||||
|
||||
@ -211,31 +214,57 @@ 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 r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
|
||||
counter += 1;
|
||||
r
|
||||
});
|
||||
// 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.
|
||||
|
||||
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)
|
||||
} else {
|
||||
None
|
||||
@ -243,11 +272,38 @@ pub fn resolve_interior<'a, 'tcx>(
|
||||
})
|
||||
.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.
|
||||
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()));
|
||||
|
||||
|
@ -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,
|
||||
|
@ -89,10 +89,13 @@ fn from_early_bound_and_free_regions<'tcx>(
|
||||
};
|
||||
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";
|
||||
|
@ -738,7 +738,7 @@ fn canonical_var_for_region(
|
||||
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)
|
||||
}
|
||||
|
@ -207,9 +207,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),
|
||||
|
@ -10,6 +10,7 @@
|
||||
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 @@ fn tcx(&self) -> TyCtxt<'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> {
|
||||
|
@ -68,7 +68,7 @@ pub(super) fn try_report_named_anon_conflict(
|
||||
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");
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
@ -336,8 +336,10 @@ pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
|
||||
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
|
||||
|
@ -598,7 +598,7 @@ pub fn anonymize_late_bound_regions<T>(self, sig: Binder<'tcx, T>) -> Binder<'tc
|
||||
.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 @@ pub fn anonymize_late_bound_regions<T>(self, sig: Binder<'tcx, T>) -> Binder<'tc
|
||||
})
|
||||
.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 @@ fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'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))
|
||||
|
@ -2115,7 +2115,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'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 @@ fn name_by_region_index(
|
||||
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 @@ fn name_by_region_index(
|
||||
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 {
|
||||
|
@ -68,7 +68,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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)
|
||||
|
@ -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)
|
||||
///
|
||||
|
@ -218,7 +218,7 @@ fn in_binder<'a, T>(
|
||||
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 @@ fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Erro
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -1971,6 +1971,7 @@ fn copy_clone_conditions(
|
||||
/// 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>>,
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -498,13 +498,13 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> {
|
||||
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 @@ fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'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 @@ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
39
src/test/ui/generic-associated-types/bugs/issue-100013.rs
Normal file
39
src/test/ui/generic-associated-types/bugs/issue-100013.rs
Normal 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() {}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user