diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 4d251cf7ac7..c044dbaba47 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -251,7 +251,8 @@ pub(crate) fn give_region_a_name(&self, fr: RegionVid) -> Option { .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)); + .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr)); if let Some(ref value) = value { self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); @@ -869,13 +870,8 @@ fn give_name_if_anonymous_region_appears_in_impl_signature( return None; } - let mut found = false; - tcx.fold_regions(tcx.type_of(region_parent), |r: ty::Region<'tcx>, _| { - if *r == ty::ReEarlyBound(region) { - found = true; - } - r - }); + let found = tcx + .any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region)); Some(RegionName { name: self.synthesize_region_name(), @@ -888,4 +884,92 @@ fn give_name_if_anonymous_region_appears_in_impl_signature( ), }) } + + fn give_name_if_anonymous_region_appears_in_arg_position_impl_trait( + &self, + fr: RegionVid, + ) -> Option { + let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { + return None; + }; + if region.has_name() { + return None; + }; + + let predicates = self + .infcx + .tcx + .predicates_of(self.body.source.def_id()) + .instantiate_identity(self.infcx.tcx) + .predicates; + + if let Some(upvar_index) = self + .regioncx + .universal_regions() + .defining_ty + .upvar_tys() + .position(|ty| self.any_param_predicate_mentions(&predicates, ty, region)) + { + let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( + self.infcx.tcx, + &self.upvars, + upvar_index, + ); + let region_name = self.synthesize_region_name(); + + Some(RegionName { + name: region_name, + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), + }) + } else if let Some(arg_index) = self + .regioncx + .universal_regions() + .unnormalized_input_tys + .iter() + .position(|ty| self.any_param_predicate_mentions(&predicates, *ty, region)) + { + let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region( + self.body, + &self.local_names, + arg_index, + ); + let region_name = self.synthesize_region_name(); + + Some(RegionName { + name: region_name, + source: RegionNameSource::AnonRegionFromArgument( + RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()), + ), + }) + } else { + None + } + } + + fn any_param_predicate_mentions( + &self, + predicates: &[ty::Predicate<'tcx>], + ty: Ty<'tcx>, + region: ty::EarlyBoundRegion, + ) -> bool { + let tcx = self.infcx.tcx; + ty.walk().any(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Param(_) = ty.kind() + { + predicates.iter().any(|pred| { + match pred.kind().skip_binder() { + ty::PredicateKind::Trait(data) if data.self_ty() == ty => {} + ty::PredicateKind::Projection(data) if data.projection_ty.self_ty() == ty => {} + _ => return false, + } + tcx.any_free_region_meets(pred, |r| { + *r == ty::ReEarlyBound(region) + }) + }) + } else { + false + } + }) + } } diff --git a/src/test/ui/borrowck/anonymous-region-in-apit.rs b/src/test/ui/borrowck/anonymous-region-in-apit.rs new file mode 100644 index 00000000000..7799a7cb151 --- /dev/null +++ b/src/test/ui/borrowck/anonymous-region-in-apit.rs @@ -0,0 +1,12 @@ +#![feature(anonymous_lifetime_in_impl_trait)] + +trait Foo { + fn bar(self, baz: T); +} + +fn qux(foo: impl Foo<&str>) { + |baz: &str| foo.bar(baz); + //~^ ERROR borrowed data escapes outside of closure +} + +fn main() {} diff --git a/src/test/ui/borrowck/anonymous-region-in-apit.stderr b/src/test/ui/borrowck/anonymous-region-in-apit.stderr new file mode 100644 index 00000000000..9e100f8ac3c --- /dev/null +++ b/src/test/ui/borrowck/anonymous-region-in-apit.stderr @@ -0,0 +1,16 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/anonymous-region-in-apit.rs:8:17 + | +LL | fn qux(foo: impl Foo<&str>) { + | --- lifetime `'2` appears in the type of `foo` +LL | |baz: &str| foo.bar(baz); + | --- - ^^^^^^^^^^^^ + | | | | + | | | `baz` escapes the closure body here + | | | argument requires that `'1` must outlive `'2` + | | let's call the lifetime of this reference `'1` + | `baz` is a reference that is only valid in the closure body + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`.