From 00e314d5edb735baef84c314c8c1a53587911887 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 17 Oct 2022 22:08:15 -0400 Subject: [PATCH 1/3] Add an optional Span to BrAnon and use it to print better error for HRTB error from generator interior --- .../src/diagnostics/bound_region_errors.rs | 3 + .../src/diagnostics/region_name.rs | 2 +- .../rustc_hir_analysis/src/astconv/mod.rs | 4 +- .../rustc_hir_analysis/src/check/intrinsic.rs | 17 ++-- .../src/generator_interior/mod.rs | 88 ++++++++++++++----- compiler/rustc_hir_typeck/src/lib.rs | 1 + .../src/errors/note_and_explain.rs | 7 +- .../src/infer/canonical/canonicalizer.rs | 2 +- .../src/infer/error_reporting/mod.rs | 7 +- .../error_reporting/nice_region_error/mod.rs | 5 +- .../nice_region_error/named_anon_conflict.rs | 2 +- .../nice_region_error/placeholder_relation.rs | 78 ++++++++++++++++ compiler/rustc_middle/src/infer/canonical.rs | 6 +- compiler/rustc_middle/src/ty/fold.rs | 8 +- compiler/rustc_middle/src/ty/print/pretty.rs | 8 +- .../rustc_middle/src/ty/structural_impls.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 4 +- .../src/traits/select/mod.rs | 1 + compiler/rustc_traits/src/chalk/db.rs | 2 +- compiler/rustc_traits/src/chalk/lowering.rs | 20 +++-- .../bugs/issue-100013.rs | 22 +++++ .../bugs/issue-100013.stderr | 23 +++++ 23 files changed, 251 insertions(+), 63 deletions(-) create mode 100644 compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs create mode 100644 src/test/ui/generic-associated-types/bugs/issue-100013.rs create mode 100644 src/test/ui/generic-associated-types/bugs/issue-100013.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index dac6abe37f5..897a161f785 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -158,6 +158,7 @@ trait TypeOpInfo<'tcx> { error_region: Option>, ) -> Option>; + #[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>, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index c044dbaba47..f9741bacd17 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -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, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 8b1cc50a3a1..0e3d318dc4c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -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 diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 609095c9cea..69e54b41d4c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -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) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index b7dd599cd43..06f6d840990 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -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 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 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)); + r + }); + 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 = 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())); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d1762598a52..93c58475cfc 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -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, diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 6a29d85627a..7aaa5ce2f42 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -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"; diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index aa44d582fd6..3dc0d60b1eb 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -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) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9ff703e521f..8a509cb8287 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -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), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index aaf5a7af00a..8a0e332f9c7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -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> { // 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 { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 76cb76d9ff4..3fe7c1598fc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -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"); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs new file mode 100644 index 00000000000..7f39de1944f --- /dev/null +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs @@ -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> { + 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, + } + } +} diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 8d1ed4b2a52..0331d764b38 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -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 diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index a329753726e..2842b3c3102 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -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)) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index fab85c39d25..c8815537835 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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 { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index f2070869ce0..9f0598d0ba8 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -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) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5f108bf0ef3..49d82b503a4 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -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), /// Named region parameters for functions (a in &'a T) /// diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 2109b3c2496..e540e2f2a21 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -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; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 84be1ced520..debf0659345 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1975,6 +1975,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] /// Zed 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>>, diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 2035252fe39..07f92299f72 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -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() } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 0492e94b94e..b64d53e60de 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -498,13 +498,13 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime 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 { 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); } } diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.rs b/src/test/ui/generic-associated-types/bugs/issue-100013.rs new file mode 100644 index 00000000000..f995591d76c --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-100013.rs @@ -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() -> impl Send { + async { // a generator checked for autotrait impl `Send` + //~^ lifetime bound not satisfied + let x = None::>; // a type referencing GAT + async {}.await; // a yield point + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr new file mode 100644 index 00000000000..11d149faa8f --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr @@ -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::>; // 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::>; // a type referencing GAT + | ^^ +note: ...must outlive the lifetime defined here + --> $DIR/issue-100013.rs:17:34 + | +LL | let x = None::>; // a type referencing GAT + | ^^ + +error: aborting due to previous error + From cececca7c7fdae8730027615c2e89120e40bac66 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Tue, 18 Oct 2022 20:08:13 -0400 Subject: [PATCH 2/3] Get spans for a couple more region types, add some optimizations, and extend test --- .../src/generator_interior/mod.rs | 82 +++++++++++-------- .../nice_region_error/placeholder_relation.rs | 2 +- .../bugs/issue-100013.rs | 19 ++++- .../bugs/issue-100013.stderr | 60 +++++++++++++- 4 files changed, 126 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 06f6d840990..7bbfb70f2c3 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -15,9 +15,11 @@ 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::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; @@ -226,6 +228,12 @@ pub fn resolve_interior<'a, 'tcx>( // typeck had previously found constraints that would cause them to be related. 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() { @@ -233,25 +241,24 @@ pub fn resolve_interior<'a, 'tcx>( 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 } + mk_bound_region(Some(span)) } + _ => mk_bound_region(None), } } - _ => { - let kind = ty::BrAnon(counter, None); - let var = ty::BoundVar::from_u32(counter); - counter += 1; - ty::BoundRegion { var, kind } + // 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 @@ -265,25 +272,34 @@ pub fn resolve_interior<'a, 'tcx>( }) .collect(); - let mut bound_vars: Vec = vec![]; + let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![]; 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 - }); + // 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)); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs index 7f39de1944f..d0813ccd3b4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs @@ -61,7 +61,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ); } (Some(sub_span), Some(sup_span), _, _) => { - err.span_note(sub_span, format!("the lifetime defined here, ...")); + err.span_note(sub_span, format!("the lifetime defined here...")); err.span_note( sup_span, format!("...must outlive the lifetime defined here"), diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.rs b/src/test/ui/generic-associated-types/bugs/issue-100013.rs index f995591d76c..fc4e47a3ba1 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-100013.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-100013.rs @@ -11,7 +11,7 @@ pub trait FutureIterator { 's: 'cx; } -fn call_2() -> impl Send { +fn call() -> impl Send { async { // a generator checked for autotrait impl `Send` //~^ lifetime bound not satisfied let x = None::>; // a type referencing GAT @@ -19,4 +19,21 @@ fn call_2() -> impl Send { } } +fn call2<'a, 'b, I: FutureIterator>() -> impl Send { + async { // a generator checked for autotrait impl `Send` + //~^ lifetime bound not satisfied + let x = None::>; // 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::>; // a type referencing GAT + async {}.await; // a yield point + } +} + fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr index 11d149faa8f..d9fcf8c48e2 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr @@ -8,7 +8,7 @@ LL | | async {}.await; // a yield point LL | | } | |_____^ | -note: the lifetime defined here, ... +note: the lifetime defined here... --> $DIR/issue-100013.rs:17:38 | LL | let x = None::>; // a type referencing GAT @@ -19,5 +19,61 @@ note: ...must outlive the lifetime defined here LL | let x = None::>; // a type referencing GAT | ^^ -error: aborting due to previous error +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::>; // 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 { + | ^^ + +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::>; // 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::>; // 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 { + | ^^ + +error: aborting due to 4 previous errors From 3c71fafd6d515004ebfd041d125338b6b82fddf9 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 7 Nov 2022 17:52:08 -0500 Subject: [PATCH 3/3] Add a known that this is a known limitation --- .../error_reporting/nice_region_error/placeholder_relation.rs | 1 + src/test/ui/generic-associated-types/bugs/issue-100013.stderr | 3 +++ 2 files changed, 4 insertions(+) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs index d0813ccd3b4..c42240f2172 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs @@ -69,6 +69,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { } _ => {} } + err.note("this is a known limitation that will be removed in the future (see issue #100013 for more information)"); Some(err) } diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr index d9fcf8c48e2..72ae288dcab 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr @@ -18,6 +18,7 @@ note: ...must outlive the lifetime defined here | LL | let x = None::>; // a type referencing GAT | ^^ + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) error: lifetime bound not satisfied --> $DIR/issue-100013.rs:23:5 @@ -40,6 +41,7 @@ note: ...must outlive the lifetime defined here | 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 for more information) error: lifetime may not live long enough --> $DIR/issue-100013.rs:25:17 @@ -74,6 +76,7 @@ note: ...must outlive the lifetime defined here | 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 for more information) error: aborting due to 4 previous errors