From 3af3566773decfc48e6f81230129a403f6aa94d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 12 Sep 2026 21:35:57 +0000 Subject: [PATCH 1/2] Detect when unmet lifetime obligation comes from use of `Self` literal When using `Self { ... }`, it introduces lifetime requirements from the `impl` that might be more strict than using the actual type's literal. We now point that out. ``` error: lifetime may not live long enough --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:21:25 | LL | impl<'a> Path<'a> { | -- lifetime `'a` defined here ... LL | pub fn sub(&mut self) -> Path/*<'_>*/ { | - let's call the lifetime of this reference `'1` ... LL | Self { | ---- requires lifetime `'a` from the `impl` ... LL | string: self.string, | ^^^^^^^^^^^ this usage requires that `'1` must outlive `'a` | help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` | LL - Self { LL + Path { | ``` --- .../src/diagnostics/region_errors.rs | 149 ++++++++++++++++++ ...ime-bounds-from-impl-in-self-literal.fixed | 91 +++++++++++ ...fetime-bounds-from-impl-in-self-literal.rs | 91 +++++++++++ ...me-bounds-from-impl-in-self-literal.stderr | 122 ++++++++++++++ tests/ui/borrowck/issue-102209.stderr | 20 ++- tests/ui/nll/issue-98170.fixed | 28 ++++ tests/ui/nll/issue-98170.rs | 3 + tests/ui/nll/issue-98170.stderr | 28 +++- .../user-annotations/normalization-self.fixed | 28 ++++ .../user-annotations/normalization-self.rs | 2 + .../normalization-self.stderr | 40 ++++- 11 files changed, 588 insertions(+), 14 deletions(-) create mode 100644 tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed create mode 100644 tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs create mode 100644 tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr create mode 100644 tests/ui/nll/issue-98170.fixed create mode 100644 tests/ui/nll/user-annotations/normalization-self.fixed diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 9bb60d47ac849..8070d4798e878 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -16,6 +16,7 @@ use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::{ self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, fold_regions, + print, }; use rustc_span::{Ident, Span, Symbol, bug, kw}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -992,6 +993,11 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { self.suggest_move_on_borrowing_closure(&mut diag); self.suggest_deref_closure_return(&mut diag); self.point_at_dyn_trait_in_field_def(&mut diag, *span, *outlived_fr); + self.detect_self_ty(&mut diag, *span, category, outlived_fr_name); + + // FIXME(estebank): we should detect when a lifetime obligation comes from a return type + // that has a hidden implicit `'_` lifetime, like when using `Type` when + // it was declared `struct Type<'a>(&'a ());`. diag } @@ -1155,6 +1161,149 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { } } + /// Detect lifetime errors caused by lifetime requirements coming from the enclosing `impl` + /// because of the use of `Self` as a binding type or as a struct/enum literal. + /// + /// Point at the `Self` in literals as the introduction of lifetime requirement: + /// ```text + /// LL | Self { + /// | ---- requires lifetime `'a` from the `impl` + /// ``` + /// + /// Provide structured suggestion to use the self type directly. + /// + /// Struct literal: + /// ```text + /// help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + /// | + /// LL - Self { + /// LL + Path { + /// | + /// ``` + /// + /// Tuple struct literal: + /// ```text + /// help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + /// | + /// LL - Self( + /// LL + Path( + /// | + /// ``` + /// + /// `Self` type: + /// ```text + /// help: consider using the type directly instead, to avoid conflicting lifetime bounds from the `impl` + /// | + /// LL - let x: Self = Path( + /// LL + let x: Path<'_> = Path( + /// | + /// ``` + fn detect_self_ty( + &self, + diag: &mut Diag<'_>, + target: Span, + category: &ConstraintCategory<'_>, + outlived_fr_name: RegionName, + ) { + struct V<'tcx> { + target: Span, + tcx: TyCtxt<'tcx>, + } + use std::ops::ControlFlow; + impl<'tcx> Visitor<'tcx> for V<'tcx> { + type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; + type Result = ControlFlow; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) -> Self::Result { + if ty.span == self.target { + return ControlFlow::Break(ty.hir_id); + } + hir::intravisit::walk_ty(self, ty) + } + + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result { + if ex.span == self.target { + return ControlFlow::Break(ex.hir_id); + } + hir::intravisit::walk_expr(self, ex) + } + } + let tcx = self.infcx.tcx; + let mut v = V { target, tcx }; + let body = tcx.hir_body_owned_by(self.mir_def_id()); + if let Some(hir_id) = v.visit_body(body).break_value() { + let node = tcx.hir_node(hir_id); + if let ConstraintCategory::TypeAnnotation(_) = category + && let hir::Node::Ty(ty) = node + && let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind + && let hir::def::Res::SelfTyAlias { alias_to, .. } + | hir::def::Res::SelfCtor(alias_to) = path.res + { + // Look for `let binding: Self = ...;`. + let ty = tcx.erase_and_anonymize_regions( + tcx.type_of(alias_to).instantiate_identity().skip_norm_wip(), + ); + diag.span_suggestion_verbose( + path.span, + "consider using the type directly instead, to avoid conflicting lifetime \ + bounds from the `impl`", + print::with_forced_trimmed_paths!(format!("{ty}")), + Applicability::MaybeIncorrect, + ); + } else { + // Look for `Self { ... }` and `Self(...)` literals. + for (_, node) in tcx.hir_parent_iter(hir_id) { + let expr = match node { + hir::Node::Expr(expr) => expr, + hir::Node::Stmt(stmt) + if let hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) = + stmt.kind => + { + expr + } + _ => continue, + }; + let path = match expr.kind { + hir::ExprKind::Struct(hir::QPath::Resolved(None, path), _, _) => path, + hir::ExprKind::Call(expr, _) + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = + expr.kind => + { + path + } + _ => continue, + }; + let (hir::def::Res::SelfTyAlias { alias_to, .. } + | hir::def::Res::SelfCtor(alias_to)) = path.res + else { + continue; + }; + diag.span_label( + path.span, + format!("requires lifetime `{outlived_fr_name}` from the `impl`"), + ); + + if let ty::Adt(adt, _args) = + tcx.type_of(alias_to).instantiate_identity().skip_norm_wip().kind() + { + diag.span_suggestion_verbose( + path.span, + "consider using the type's name directly instead, to avoid conflicting \ + lifetime bounds from the `impl`", + format!("{}", tcx.item_name(adt.did())), + Applicability::MaybeIncorrect, + ); + } + break; + } + } + } + } + /// Adds a suggestion to errors where an `impl Trait` is returned. /// /// ```text diff --git a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed new file mode 100644 index 0000000000000..05de7603560b7 --- /dev/null +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed @@ -0,0 +1,91 @@ +// https://github.com/rust-lang/rust/issues/101393 +//@ run-rustfix +#![allow(unused, mismatched_lifetime_syntaxes)] + +mod _struct { + pub struct Path<'a> { + string: &'a mut String, + } + + impl<'a> Path<'a> { + //~^ NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + pub fn sub(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + // FIXME(estebank): we should extend the diagnostic to mention that `Path` in the + // return type has a hidden `'_` lifetime in it. + Path { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + } + } + pub fn sup(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x = Path { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + }; + x + } + pub fn soup(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x: Path<'_> = Path { + //~^ ERROR: lifetime may not live long enough + //~| NOTE: type annotation requires that `'1` must outlive `'a` + //~| HELP: consider using the type directly instead + string: self.string, + }; + x + } + } +} + +mod tuple_struct { + pub struct Path<'a>(&'a mut String); + + impl<'a> Path<'a> { + //~^ NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + pub fn sub(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + Path( + //~^ HELP: consider using the type's name directly instead + //~| NOTE: requires lifetime `'a` from the `impl` + self.0, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + ) + } + pub fn sup(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x = Path( + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + self.0, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + ); + x + } + pub fn soup(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x: Path<'_> = Path( + //~^ ERROR: lifetime may not live long enough + //~| NOTE: type annotation requires that `'1` must outlive `'a` + //~| HELP: consider using the type directly instead + self.0, + ); + x + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs new file mode 100644 index 0000000000000..797e0fbbfab91 --- /dev/null +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs @@ -0,0 +1,91 @@ +// https://github.com/rust-lang/rust/issues/101393 +//@ run-rustfix +#![allow(unused, mismatched_lifetime_syntaxes)] + +mod _struct { + pub struct Path<'a> { + string: &'a mut String, + } + + impl<'a> Path<'a> { + //~^ NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + pub fn sub(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + // FIXME(estebank): we should extend the diagnostic to mention that `Path` in the + // return type has a hidden `'_` lifetime in it. + Self { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + } + } + pub fn sup(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x = Self { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + }; + x + } + pub fn soup(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x: Self = Path { + //~^ ERROR: lifetime may not live long enough + //~| NOTE: type annotation requires that `'1` must outlive `'a` + //~| HELP: consider using the type directly instead + string: self.string, + }; + x + } + } +} + +mod tuple_struct { + pub struct Path<'a>(&'a mut String); + + impl<'a> Path<'a> { + //~^ NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + pub fn sub(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + Self( + //~^ HELP: consider using the type's name directly instead + //~| NOTE: requires lifetime `'a` from the `impl` + self.0, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + ) + } + pub fn sup(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x = Self( + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + self.0, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + ); + x + } + pub fn soup(&mut self) -> Path/*<'_>*/ { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x: Self = Path( + //~^ ERROR: lifetime may not live long enough + //~| NOTE: type annotation requires that `'1` must outlive `'a` + //~| HELP: consider using the type directly instead + self.0, + ); + x + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr new file mode 100644 index 0000000000000..4284ef0470762 --- /dev/null +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr @@ -0,0 +1,122 @@ +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:21:25 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +LL | pub fn sub(&mut self) -> Path/*<'_>*/ { + | - let's call the lifetime of this reference `'1` +... +LL | Self { + | ---- requires lifetime `'a` from the `impl` +... +LL | string: self.string, + | ^^^^^^^^^^^ this usage requires that `'1` must outlive `'a` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - Self { +LL + Path { + | + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:31:25 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +LL | pub fn sup(&mut self) -> Path/*<'_>*/ { + | - let's call the lifetime of this reference `'1` +LL | +LL | let x = Self { + | ---- requires lifetime `'a` from the `impl` +... +LL | string: self.string, + | ^^^^^^^^^^^ this usage requires that `'1` must outlive `'a` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - let x = Self { +LL + let x = Path { + | + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:39:20 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +LL | pub fn soup(&mut self) -> Path/*<'_>*/ { + | - let's call the lifetime of this reference `'1` +LL | +LL | let x: Self = Path { + | ^^^^ type annotation requires that `'1` must outlive `'a` + | +help: consider using the type directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - let x: Self = Path { +LL + let x: Path<'_> = Path { + | + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:62:17 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +LL | pub fn sub(&mut self) -> Path/*<'_>*/ { + | - let's call the lifetime of this reference `'1` +LL | +LL | Self( + | ---- requires lifetime `'a` from the `impl` +... +LL | self.0, + | ^^^^^^ this usage requires that `'1` must outlive `'a` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - Self( +LL + Path( + | + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:72:17 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +LL | pub fn sup(&mut self) -> Path/*<'_>*/ { + | - let's call the lifetime of this reference `'1` +LL | +LL | let x = Self( + | ---- requires lifetime `'a` from the `impl` +... +LL | self.0, + | ^^^^^^ this usage requires that `'1` must outlive `'a` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - let x = Self( +LL + let x = Path( + | + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:80:20 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +LL | pub fn soup(&mut self) -> Path/*<'_>*/ { + | - let's call the lifetime of this reference `'1` +LL | +LL | let x: Self = Path( + | ^^^^ type annotation requires that `'1` must outlive `'a` + | +help: consider using the type directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - let x: Self = Path( +LL + let x: Path<'_> = Path( + | + +error: aborting due to 6 previous errors + diff --git a/tests/ui/borrowck/issue-102209.stderr b/tests/ui/borrowck/issue-102209.stderr index 351de8217b234..862de8176127b 100644 --- a/tests/ui/borrowck/issue-102209.stderr +++ b/tests/ui/borrowck/issue-102209.stderr @@ -7,7 +7,15 @@ LL | pub fn with) -> R>(f: F) -> R { LL | Brand::with(|brand| { | ----- has type `Brand<'1>` LL | f(Self { brand: brand.lt }) - | ^^^^^^^^ this usage requires that `'1` must outlive `'2` + | ---- ^^^^^^^^ this usage requires that `'1` must outlive `'2` + | | + | requires lifetime `'2` from the `impl` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - f(Self { brand: brand.lt }) +LL + f(NfaBuilder { brand: brand.lt }) + | error: lifetime may not live long enough --> $DIR/issue-102209.rs:10:29 @@ -16,7 +24,15 @@ LL | impl NfaBuilder<'_> { | -- lifetime `'1` appears in the `impl`'s self type ... LL | f(Self { brand: brand.lt }) - | ^^^^^^^^ this usage requires that `'1` must outlive `'static` + | ---- ^^^^^^^^ this usage requires that `'1` must outlive `'static` + | | + | requires lifetime `'static` from the `impl` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - f(Self { brand: brand.lt }) +LL + f(NfaBuilder { brand: brand.lt }) + | error: aborting due to 2 previous errors diff --git a/tests/ui/nll/issue-98170.fixed b/tests/ui/nll/issue-98170.fixed new file mode 100644 index 0000000000000..e4ec33323ddcf --- /dev/null +++ b/tests/ui/nll/issue-98170.fixed @@ -0,0 +1,28 @@ +//@run-rustfix +#![allow(unused)] + +pub struct MyStruct<'a> { + field: &'a [u32], +} + +impl MyStruct<'_> { + pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> { + MyStruct { field } + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + } +} + +trait Trait<'a> { + fn new(field: &'a [u32]) -> MyStruct<'a>; +} + +impl<'a> Trait<'a> for MyStruct<'_> { + fn new(field: &'a [u32]) -> MyStruct<'a> { + MyStruct { field } + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + } +} + +fn main() {} diff --git a/tests/ui/nll/issue-98170.rs b/tests/ui/nll/issue-98170.rs index 6bb12f52d3f3e..e8c017e3f4fcd 100644 --- a/tests/ui/nll/issue-98170.rs +++ b/tests/ui/nll/issue-98170.rs @@ -1,3 +1,6 @@ +//@run-rustfix +#![allow(unused)] + pub struct MyStruct<'a> { field: &'a [u32], } diff --git a/tests/ui/nll/issue-98170.stderr b/tests/ui/nll/issue-98170.stderr index 0d17365e71b4a..a5a03a8642684 100644 --- a/tests/ui/nll/issue-98170.stderr +++ b/tests/ui/nll/issue-98170.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-98170.rs:7:9 + --> $DIR/issue-98170.rs:10:9 | LL | impl MyStruct<'_> { | -- lifetime `'1` appears in the `impl`'s self type @@ -9,17 +9,25 @@ LL | Self { field } | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` error: lifetime may not live long enough - --> $DIR/issue-98170.rs:7:16 + --> $DIR/issue-98170.rs:10:16 | LL | impl MyStruct<'_> { | -- lifetime `'1` appears in the `impl`'s self type LL | pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> { | -- lifetime `'a` defined here LL | Self { field } - | ^^^^^ this usage requires that `'a` must outlive `'1` + | ---- ^^^^^ this usage requires that `'a` must outlive `'1` + | | + | requires lifetime `'1` from the `impl` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - Self { field } +LL + MyStruct { field } + | error: lifetime may not live long enough - --> $DIR/issue-98170.rs:19:9 + --> $DIR/issue-98170.rs:22:9 | LL | impl<'a> Trait<'a> for MyStruct<'_> { | -- -- lifetime `'1` appears in the `impl`'s self type @@ -30,7 +38,7 @@ LL | Self { field } | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` error: lifetime may not live long enough - --> $DIR/issue-98170.rs:19:16 + --> $DIR/issue-98170.rs:22:16 | LL | impl<'a> Trait<'a> for MyStruct<'_> { | -- -- lifetime `'1` appears in the `impl`'s self type @@ -38,7 +46,15 @@ LL | impl<'a> Trait<'a> for MyStruct<'_> { | lifetime `'a` defined here LL | fn new(field: &'a [u32]) -> MyStruct<'a> { LL | Self { field } - | ^^^^^ this usage requires that `'a` must outlive `'1` + | ---- ^^^^^ this usage requires that `'a` must outlive `'1` + | | + | requires lifetime `'1` from the `impl` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - Self { field } +LL + MyStruct { field } + | error: aborting due to 4 previous errors diff --git a/tests/ui/nll/user-annotations/normalization-self.fixed b/tests/ui/nll/user-annotations/normalization-self.fixed new file mode 100644 index 0000000000000..c530e326e2c1f --- /dev/null +++ b/tests/ui/nll/user-annotations/normalization-self.fixed @@ -0,0 +1,28 @@ +//@ check-fail +//@ run-rustfix +#![allow(unused)] + +trait Trait { type Assoc; } +impl<'a> Trait for &'a () { type Assoc = &'a (); } + +struct MyTuple(T); +impl MyTuple<<&'static () as Trait>::Assoc> { + fn test(x: &(), y: &()) { + MyTuple(x); + //~^ ERROR + let _: MyTuple<<&() as Trait>::Assoc> = MyTuple(y); + //~^ ERROR + } +} + +struct MyStruct { val: T, } +impl MyStruct<<&'static () as Trait>::Assoc> { + fn test(x: &(), y: &()) { + MyStruct { val: x }; + //~^ ERROR + let _: MyStruct<<&() as Trait>::Assoc> = MyStruct { val: y }; + //~^ ERROR + } +} + +fn main() {} diff --git a/tests/ui/nll/user-annotations/normalization-self.rs b/tests/ui/nll/user-annotations/normalization-self.rs index ebe12b248e85c..b9ffe7953837e 100644 --- a/tests/ui/nll/user-annotations/normalization-self.rs +++ b/tests/ui/nll/user-annotations/normalization-self.rs @@ -1,4 +1,6 @@ //@ check-fail +//@ run-rustfix +#![allow(unused)] trait Trait { type Assoc; } impl<'a> Trait for &'a () { type Assoc = &'a (); } diff --git a/tests/ui/nll/user-annotations/normalization-self.stderr b/tests/ui/nll/user-annotations/normalization-self.stderr index e231ed03c2eea..6cdb327251720 100644 --- a/tests/ui/nll/user-annotations/normalization-self.stderr +++ b/tests/ui/nll/user-annotations/normalization-self.stderr @@ -1,36 +1,64 @@ error: lifetime may not live long enough - --> $DIR/normalization-self.rs:9:14 + --> $DIR/normalization-self.rs:11:14 | LL | fn test(x: &(), y: &()) { | - let's call the lifetime of this reference `'1` LL | Self(x); - | ^ this usage requires that `'1` must outlive `'static` + | ---- ^ this usage requires that `'1` must outlive `'static` + | | + | requires lifetime `'static` from the `impl` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - Self(x); +LL + MyTuple(x); + | error: lifetime may not live long enough - --> $DIR/normalization-self.rs:11:16 + --> $DIR/normalization-self.rs:13:16 | LL | fn test(x: &(), y: &()) { | - let's call the lifetime of this reference `'2` ... LL | let _: Self = MyTuple(y); | ^^^^ type annotation requires that `'2` must outlive `'static` + | +help: consider using the type directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - let _: Self = MyTuple(y); +LL + let _: MyTuple<<&() as Trait>::Assoc> = MyTuple(y); + | error: lifetime may not live long enough - --> $DIR/normalization-self.rs:19:21 + --> $DIR/normalization-self.rs:21:21 | LL | fn test(x: &(), y: &()) { | - let's call the lifetime of this reference `'1` LL | Self { val: x }; - | ^ this usage requires that `'1` must outlive `'static` + | ---- ^ this usage requires that `'1` must outlive `'static` + | | + | requires lifetime `'static` from the `impl` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - Self { val: x }; +LL + MyStruct { val: x }; + | error: lifetime may not live long enough - --> $DIR/normalization-self.rs:21:16 + --> $DIR/normalization-self.rs:23:16 | LL | fn test(x: &(), y: &()) { | - let's call the lifetime of this reference `'2` ... LL | let _: Self = MyStruct { val: y }; | ^^^^ type annotation requires that `'2` must outlive `'static` + | +help: consider using the type directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - let _: Self = MyStruct { val: y }; +LL + let _: MyStruct<<&() as Trait>::Assoc> = MyStruct { val: y }; + | error: aborting due to 4 previous errors From ec0dd46e47e6877e6117e98af99edb3f978ef52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 13 Sep 2026 23:13:23 +0000 Subject: [PATCH 2/2] Point at return type with implicit lifetime and suggest making it explicit ``` error: lifetime may not live long enough --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:21:25 | LL | impl<'a> Path<'a> { | -- lifetime `'a` defined here ... LL | pub fn sub(&mut self) -> Path { | - ---- this returned type has an implicit lifetime `'1` | | | let's call the lifetime of this reference `'1` ... LL | Self { | ---- requires lifetime `'a` from the `impl` ... LL | string: self.string, | ^^^^^^^^^^^ this usage requires that `'1` must outlive `'a` | help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` | LL - Self { LL + Path { | help: consider making explicit the implicit `'1` lifetime in the return type | LL | pub fn sub(&mut self) -> Path<'_> { | ++++ ``` --- .../src/diagnostics/region_errors.rs | 94 +++++++++- ...ime-bounds-from-impl-in-self-literal.fixed | 91 +++++++-- ...fetime-bounds-from-impl-in-self-literal.rs | 91 +++++++-- ...me-bounds-from-impl-in-self-literal.stderr | 172 +++++++++++++++--- .../ui/nll/outlives-suggestion-simple.stderr | 8 +- 5 files changed, 408 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 8070d4798e878..b932996e232ad 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -994,10 +994,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { self.suggest_deref_closure_return(&mut diag); self.point_at_dyn_trait_in_field_def(&mut diag, *span, *outlived_fr); self.detect_self_ty(&mut diag, *span, category, outlived_fr_name); - - // FIXME(estebank): we should detect when a lifetime obligation comes from a return type - // that has a hidden implicit `'_` lifetime, like when using `Type` when - // it was declared `struct Type<'a>(&'a ());`. + self.point_at_implicit_lifetime_in_return_type(&mut diag, *fr, fr_name); diag } @@ -1161,6 +1158,95 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { } } + /// Point at `Path` in return type when declared `struct Path<'a>(&'a ());`. + /// + /// ```text + /// LL | pub fn sub(&mut self) -> Path { + /// | - ---- this returned type has an implicit lifetime `'1` + /// | | + /// | let's call the lifetime of this reference `'1` + /// ... + /// help: consider making explicit the implicit `'1` lifetime in the return type + /// | + /// LL | pub fn sub(&mut self) -> Path<'_> { + /// | ++++ + /// ``` + fn point_at_implicit_lifetime_in_return_type( + &self, + diag: &mut Diag<'_>, + fr: RegionVid, + fr_name: RegionName, + ) { + let body = self.infcx.tcx.hir_body_owned_by(self.mir_def_id()); + let expr = &body.value.peel_blocks(); + if let Some(fn_hir_id) = self.infcx.tcx.hir_get_fn_id_for_return_block(expr.hir_id) + && let Some(fn_decl) = self.infcx.tcx.hir_node(fn_hir_id).fn_decl() + && let hir::FnRetTy::Return(ret) = fn_decl.output + { + struct V<'tcx> { + lifetimes: Vec<&'tcx hir::Lifetime>, + tcx: TyCtxt<'tcx>, + } + impl<'tcx> Visitor<'tcx> for V<'tcx> { + type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + fn visit_lifetime(&mut self, lifetime: &'tcx hir::Lifetime) -> Self::Result { + self.lifetimes.push(lifetime); + hir::intravisit::walk_lifetime(self, lifetime) + } + } + let tcx = self.infcx.tcx; + let mut v = V { lifetimes: vec![], tcx }; + v.visit_ty_unambig(ret); + if let Some(region) = self.regioncx.to_error_region(fr) { + for lifetime in v.lifetimes { + if let hir::LifetimeKind::Param(lt_def_id) = lifetime.kind + && lifetime.is_implicit() + && let hir::LifetimeSource::Path { angle_brackets } = lifetime.source + && let Some(def_id) = + region.opt_param_def_id(self.infcx.tcx, self.mir_def_id().to_def_id()) + && def_id == lt_def_id.to_def_id() + { + let (msg, sugg) = match angle_brackets { + hir::AngleBrackets::Missing => ( + format!("this returned type has an implicit lifetime `{fr_name}`"), + format!("<{region}>"), + ), + hir::AngleBrackets::Empty => ( + format!( + "there is an implicit lifetime `{fr_name}` in this empty \ + parameter list", + ), + format!("{region}"), + ), + hir::AngleBrackets::Full => ( + format!( + "there is an implicit lifetime `{fr_name}` in this parameter \ + list", + ), + format!("{region}, "), + ), + }; + diag.span_label(lifetime.ident.span, msg); + diag.span_suggestion_verbose( + lifetime.ident.span.shrink_to_hi(), + format!( + "consider making explicit the implicit `{fr_name}` lifetime in the \ + return type", + ), + sugg, + Applicability::MachineApplicable, + ); + } + } + } + } + } + /// Detect lifetime errors caused by lifetime requirements coming from the enclosing `impl` /// because of the use of `Self` as a binding type or as a struct/enum literal. /// diff --git a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed index 05de7603560b7..752dab16e5348 100644 --- a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed @@ -1,20 +1,20 @@ // https://github.com/rust-lang/rust/issues/101393 //@ run-rustfix -#![allow(unused, mismatched_lifetime_syntaxes)] +#![allow(unused)] mod _struct { - pub struct Path<'a> { - string: &'a mut String, + pub struct Path<'a, T = String> { + string: &'a mut T, } impl<'a> Path<'a> { //~^ NOTE lifetime `'a` defined here //~| NOTE lifetime `'a` defined here //~| NOTE lifetime `'a` defined here - pub fn sub(&mut self) -> Path/*<'_>*/ { + pub fn sub(&mut self) -> Path<'_> { //~^ NOTE: let's call the lifetime of this reference `'1` - // FIXME(estebank): we should extend the diagnostic to mention that `Path` in the - // return type has a hidden `'_` lifetime in it. + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type Path { //~^ NOTE: requires lifetime `'a` from the `impl` //~| HELP: consider using the type's name directly instead @@ -23,8 +23,10 @@ mod _struct { //~| NOTE: this usage requires that `'1` must outlive `'a` } } - pub fn sup(&mut self) -> Path/*<'_>*/ { + pub fn sup(&mut self) -> Path<'_> { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type let x = Path { //~^ NOTE: requires lifetime `'a` from the `impl` //~| HELP: consider using the type's name directly instead @@ -34,8 +36,10 @@ mod _struct { }; x } - pub fn soup(&mut self) -> Path/*<'_>*/ { + pub fn soup(&mut self) -> Path<'_> { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type let x: Path<'_> = Path { //~^ ERROR: lifetime may not live long enough //~| NOTE: type annotation requires that `'1` must outlive `'a` @@ -47,6 +51,65 @@ mod _struct { } } +mod _struct2 { + pub struct Path<'a, T = String> { + string: &'a mut T, + } + + impl<'a> Path<'a, String> { + //~^ NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + pub fn sub(&mut self) -> Path<'_, String> { + //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: there is an implicit lifetime `'1` in this parameter list + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type + Path { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + } + } + pub fn sup(&mut self) -> Path<'_> { + //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: there is an implicit lifetime `'1` in this empty parameter list + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type + let x = Path { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + }; + x + } + pub fn soup(&mut self) -> Path<'_> { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x: Path<'_> = Path { + //~^ ERROR: lifetime may not live long enough + //~| NOTE: type annotation requires that `'1` must outlive `'a` + //~| HELP: consider using the type directly instead + string: self.string, + }; + x + } + pub fn sap<'b>(&'b mut self) -> Path<'b> { + //~^ NOTE: lifetime `'b` defined here + Path { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'b` must outlive `'a` + //~| HELP: consider adding the following bound: `'b: 'a` + } + } + } +} + mod tuple_struct { pub struct Path<'a>(&'a mut String); @@ -54,8 +117,10 @@ mod tuple_struct { //~^ NOTE lifetime `'a` defined here //~| NOTE lifetime `'a` defined here //~| NOTE lifetime `'a` defined here - pub fn sub(&mut self) -> Path/*<'_>*/ { + pub fn sub(&mut self) -> Path<'_> { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type Path( //~^ HELP: consider using the type's name directly instead //~| NOTE: requires lifetime `'a` from the `impl` @@ -64,8 +129,10 @@ mod tuple_struct { //~| NOTE: this usage requires that `'1` must outlive `'a` ) } - pub fn sup(&mut self) -> Path/*<'_>*/ { + pub fn sup(&mut self) -> Path<'_> { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type let x = Path( //~^ NOTE: requires lifetime `'a` from the `impl` //~| HELP: consider using the type's name directly instead @@ -75,8 +142,10 @@ mod tuple_struct { ); x } - pub fn soup(&mut self) -> Path/*<'_>*/ { + pub fn soup(&mut self) -> Path<'_> { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type let x: Path<'_> = Path( //~^ ERROR: lifetime may not live long enough //~| NOTE: type annotation requires that `'1` must outlive `'a` diff --git a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs index 797e0fbbfab91..5a26f7e1cff29 100644 --- a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs @@ -1,20 +1,20 @@ // https://github.com/rust-lang/rust/issues/101393 //@ run-rustfix -#![allow(unused, mismatched_lifetime_syntaxes)] +#![allow(unused)] mod _struct { - pub struct Path<'a> { - string: &'a mut String, + pub struct Path<'a, T = String> { + string: &'a mut T, } impl<'a> Path<'a> { //~^ NOTE lifetime `'a` defined here //~| NOTE lifetime `'a` defined here //~| NOTE lifetime `'a` defined here - pub fn sub(&mut self) -> Path/*<'_>*/ { + pub fn sub(&mut self) -> Path { //~^ NOTE: let's call the lifetime of this reference `'1` - // FIXME(estebank): we should extend the diagnostic to mention that `Path` in the - // return type has a hidden `'_` lifetime in it. + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type Self { //~^ NOTE: requires lifetime `'a` from the `impl` //~| HELP: consider using the type's name directly instead @@ -23,8 +23,10 @@ mod _struct { //~| NOTE: this usage requires that `'1` must outlive `'a` } } - pub fn sup(&mut self) -> Path/*<'_>*/ { + pub fn sup(&mut self) -> Path { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type let x = Self { //~^ NOTE: requires lifetime `'a` from the `impl` //~| HELP: consider using the type's name directly instead @@ -34,8 +36,10 @@ mod _struct { }; x } - pub fn soup(&mut self) -> Path/*<'_>*/ { + pub fn soup(&mut self) -> Path { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type let x: Self = Path { //~^ ERROR: lifetime may not live long enough //~| NOTE: type annotation requires that `'1` must outlive `'a` @@ -47,6 +51,65 @@ mod _struct { } } +mod _struct2 { + pub struct Path<'a, T = String> { + string: &'a mut T, + } + + impl<'a> Path<'a, String> { + //~^ NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + //~| NOTE lifetime `'a` defined here + pub fn sub(&mut self) -> Path { + //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: there is an implicit lifetime `'1` in this parameter list + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type + Self { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + } + } + pub fn sup(&mut self) -> Path<> { + //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: there is an implicit lifetime `'1` in this empty parameter list + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type + let x = Self { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'1` must outlive `'a` + }; + x + } + pub fn soup(&mut self) -> Path<'_> { + //~^ NOTE: let's call the lifetime of this reference `'1` + let x: Self = Path { + //~^ ERROR: lifetime may not live long enough + //~| NOTE: type annotation requires that `'1` must outlive `'a` + //~| HELP: consider using the type directly instead + string: self.string, + }; + x + } + pub fn sap<'b>(&'b mut self) -> Path<'b> { + //~^ NOTE: lifetime `'b` defined here + Self { + //~^ NOTE: requires lifetime `'a` from the `impl` + //~| HELP: consider using the type's name directly instead + string: self.string, + //~^ ERROR: lifetime may not live long enough + //~| NOTE: this usage requires that `'b` must outlive `'a` + //~| HELP: consider adding the following bound: `'b: 'a` + } + } + } +} + mod tuple_struct { pub struct Path<'a>(&'a mut String); @@ -54,8 +117,10 @@ mod tuple_struct { //~^ NOTE lifetime `'a` defined here //~| NOTE lifetime `'a` defined here //~| NOTE lifetime `'a` defined here - pub fn sub(&mut self) -> Path/*<'_>*/ { + pub fn sub(&mut self) -> Path { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type Self( //~^ HELP: consider using the type's name directly instead //~| NOTE: requires lifetime `'a` from the `impl` @@ -64,8 +129,10 @@ mod tuple_struct { //~| NOTE: this usage requires that `'1` must outlive `'a` ) } - pub fn sup(&mut self) -> Path/*<'_>*/ { + pub fn sup(&mut self) -> Path { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type let x = Self( //~^ NOTE: requires lifetime `'a` from the `impl` //~| HELP: consider using the type's name directly instead @@ -75,8 +142,10 @@ mod tuple_struct { ); x } - pub fn soup(&mut self) -> Path/*<'_>*/ { + pub fn soup(&mut self) -> Path { //~^ NOTE: let's call the lifetime of this reference `'1` + //~| NOTE: this returned type has an implicit lifetime `'1` + //~| HELP: consider making explicit the implicit `'1` lifetime in the return type let x: Self = Path( //~^ ERROR: lifetime may not live long enough //~| NOTE: type annotation requires that `'1` must outlive `'a` diff --git a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr index 4284ef0470762..27184812e3fa8 100644 --- a/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr @@ -4,8 +4,10 @@ error: lifetime may not live long enough LL | impl<'a> Path<'a> { | -- lifetime `'a` defined here ... -LL | pub fn sub(&mut self) -> Path/*<'_>*/ { - | - let's call the lifetime of this reference `'1` +LL | pub fn sub(&mut self) -> Path { + | - ---- this returned type has an implicit lifetime `'1` + | | + | let's call the lifetime of this reference `'1` ... LL | Self { | ---- requires lifetime `'a` from the `impl` @@ -18,16 +20,22 @@ help: consider using the type's name directly instead, to avoid conflicting life LL - Self { LL + Path { | +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | pub fn sub(&mut self) -> Path<'_> { + | ++++ error: lifetime may not live long enough - --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:31:25 + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:33:25 | LL | impl<'a> Path<'a> { | -- lifetime `'a` defined here ... -LL | pub fn sup(&mut self) -> Path/*<'_>*/ { - | - let's call the lifetime of this reference `'1` -LL | +LL | pub fn sup(&mut self) -> Path { + | - ---- this returned type has an implicit lifetime `'1` + | | + | let's call the lifetime of this reference `'1` +... LL | let x = Self { | ---- requires lifetime `'a` from the `impl` ... @@ -39,14 +47,96 @@ help: consider using the type's name directly instead, to avoid conflicting life LL - let x = Self { LL + let x = Path { | +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | pub fn sup(&mut self) -> Path<'_> { + | ++++ error: lifetime may not live long enough - --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:39:20 + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:43:20 | LL | impl<'a> Path<'a> { | -- lifetime `'a` defined here ... -LL | pub fn soup(&mut self) -> Path/*<'_>*/ { +LL | pub fn soup(&mut self) -> Path { + | - ---- this returned type has an implicit lifetime `'1` + | | + | let's call the lifetime of this reference `'1` +... +LL | let x: Self = Path { + | ^^^^ type annotation requires that `'1` must outlive `'a` + | +help: consider using the type directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - let x: Self = Path { +LL + let x: Path<'_> = Path { + | +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | pub fn soup(&mut self) -> Path<'_> { + | ++++ + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:71:25 + | +LL | impl<'a> Path<'a, String> { + | -- lifetime `'a` defined here +... +LL | pub fn sub(&mut self) -> Path { + | - - there is an implicit lifetime `'1` in this parameter list + | | + | let's call the lifetime of this reference `'1` +... +LL | Self { + | ---- requires lifetime `'a` from the `impl` +... +LL | string: self.string, + | ^^^^^^^^^^^ this usage requires that `'1` must outlive `'a` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - Self { +LL + Path { + | +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | pub fn sub(&mut self) -> Path<'_, String> { + | +++ + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:83:25 + | +LL | impl<'a> Path<'a, String> { + | -- lifetime `'a` defined here +... +LL | pub fn sup(&mut self) -> Path<> { + | - - there is an implicit lifetime `'1` in this empty parameter list + | | + | let's call the lifetime of this reference `'1` +... +LL | let x = Self { + | ---- requires lifetime `'a` from the `impl` +... +LL | string: self.string, + | ^^^^^^^^^^^ this usage requires that `'1` must outlive `'a` + | +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - let x = Self { +LL + let x = Path { + | +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | pub fn sup(&mut self) -> Path<'_> { + | ++ + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:91:20 + | +LL | impl<'a> Path<'a, String> { + | -- lifetime `'a` defined here +... +LL | pub fn soup(&mut self) -> Path<'_> { | - let's call the lifetime of this reference `'1` LL | LL | let x: Self = Path { @@ -59,14 +149,38 @@ LL + let x: Path<'_> = Path { | error: lifetime may not live long enough - --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:62:17 + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:104:25 | -LL | impl<'a> Path<'a> { +LL | impl<'a> Path<'a, String> { | -- lifetime `'a` defined here ... -LL | pub fn sub(&mut self) -> Path/*<'_>*/ { - | - let's call the lifetime of this reference `'1` +LL | pub fn sap<'b>(&'b mut self) -> Path<'b> { + | -- lifetime `'b` defined here LL | +LL | Self { + | ---- requires lifetime `'a` from the `impl` +... +LL | string: self.string, + | ^^^^^^^^^^^ this usage requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` +help: consider using the type's name directly instead, to avoid conflicting lifetime bounds from the `impl` + | +LL - Self { +LL + Path { + | + +error: lifetime may not live long enough + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:127:17 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +LL | pub fn sub(&mut self) -> Path { + | - ---- this returned type has an implicit lifetime `'1` + | | + | let's call the lifetime of this reference `'1` +... LL | Self( | ---- requires lifetime `'a` from the `impl` ... @@ -78,16 +192,22 @@ help: consider using the type's name directly instead, to avoid conflicting life LL - Self( LL + Path( | +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | pub fn sub(&mut self) -> Path<'_> { + | ++++ error: lifetime may not live long enough - --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:72:17 + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:139:17 | LL | impl<'a> Path<'a> { | -- lifetime `'a` defined here ... -LL | pub fn sup(&mut self) -> Path/*<'_>*/ { - | - let's call the lifetime of this reference `'1` -LL | +LL | pub fn sup(&mut self) -> Path { + | - ---- this returned type has an implicit lifetime `'1` + | | + | let's call the lifetime of this reference `'1` +... LL | let x = Self( | ---- requires lifetime `'a` from the `impl` ... @@ -99,16 +219,22 @@ help: consider using the type's name directly instead, to avoid conflicting life LL - let x = Self( LL + let x = Path( | +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | pub fn sup(&mut self) -> Path<'_> { + | ++++ error: lifetime may not live long enough - --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:80:20 + --> $DIR/conflicting-lifetime-bounds-from-impl-in-self-literal.rs:149:20 | LL | impl<'a> Path<'a> { | -- lifetime `'a` defined here ... -LL | pub fn soup(&mut self) -> Path/*<'_>*/ { - | - let's call the lifetime of this reference `'1` -LL | +LL | pub fn soup(&mut self) -> Path { + | - ---- this returned type has an implicit lifetime `'1` + | | + | let's call the lifetime of this reference `'1` +... LL | let x: Self = Path( | ^^^^ type annotation requires that `'1` must outlive `'a` | @@ -117,6 +243,10 @@ help: consider using the type directly instead, to avoid conflicting lifetime bo LL - let x: Self = Path( LL + let x: Path<'_> = Path( | +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | pub fn soup(&mut self) -> Path<'_> { + | ++++ -error: aborting due to 6 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/nll/outlives-suggestion-simple.stderr b/tests/ui/nll/outlives-suggestion-simple.stderr index 36e4d8b43c6d6..f5e12ee652fbd 100644 --- a/tests/ui/nll/outlives-suggestion-simple.stderr +++ b/tests/ui/nll/outlives-suggestion-simple.stderr @@ -102,13 +102,19 @@ LL | impl<'a> Foo2<'a> { | -- lifetime `'a` defined here LL | // should not produce outlives suggestions to name 'self LL | fn get_bar(&self) -> Bar2 { - | - let's call the lifetime of this reference `'1` + | - ---- this returned type has an implicit lifetime `'1` + | | + | let's call the lifetime of this reference `'1` LL | Bar2::new(&self) | ^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a` | = note: requirement occurs because of the type `Foo2<'_>`, which makes the generic argument `'_` invariant = note: the struct `Foo2<'a>` is invariant over the parameter `'a` = help: see for more information about variance +help: consider making explicit the implicit `'1` lifetime in the return type + | +LL | fn get_bar(&self) -> Bar2<'_> { + | ++++ error: aborting due to 10 previous errors