diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 9bb60d47ac849..b932996e232ad 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,8 @@ 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); + self.point_at_implicit_lifetime_in_return_type(&mut diag, *fr, fr_name); diag } @@ -1155,6 +1158,238 @@ 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. + /// + /// 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..752dab16e5348 --- /dev/null +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.fixed @@ -0,0 +1,160 @@ +// https://github.com/rust-lang/rust/issues/101393 +//@ run-rustfix +#![allow(unused)] + +mod _struct { + 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<'_> { + //~^ 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 { + //~^ 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: 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 + 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` + //~| 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` + //~| HELP: consider using the type directly instead + string: self.string, + }; + x + } + } +} + +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); + + 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` + //~| 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` + 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` + //~| 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 + 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` + //~| 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` + //~| 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..5a26f7e1cff29 --- /dev/null +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.rs @@ -0,0 +1,160 @@ +// https://github.com/rust-lang/rust/issues/101393 +//@ run-rustfix +#![allow(unused)] + +mod _struct { + 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 { + //~^ 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 { + //~^ 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: 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 + 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` + //~| 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` + //~| HELP: consider using the type directly instead + string: self.string, + }; + x + } + } +} + +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); + + 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` + //~| 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` + 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` + //~| 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 + 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` + //~| 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` + //~| 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..27184812e3fa8 --- /dev/null +++ b/tests/ui/borrowck/conflicting-lifetime-bounds-from-impl-in-self-literal.stderr @@ -0,0 +1,252 @@ +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<'_> { + | ++++ + +error: lifetime may not live long enough + --> $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 { + | - ---- 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` +... +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:43:20 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +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 { + | ^^^^ 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:104:25 + | +LL | impl<'a> Path<'a, String> { + | -- lifetime `'a` defined here +... +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` +... +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( + | +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:139:17 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +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` +... +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( + | +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:149:20 + | +LL | impl<'a> Path<'a> { + | -- lifetime `'a` defined here +... +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: aborting due to 10 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/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 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