Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 7 pull requests #125331

Merged
merged 26 commits into from
May 20, 2024
Merged
Changes from 7 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c54301f
fix: Add if to check whether the previous node is Block
cardigan1008 May 9, 2024
62318b3
fix: Check whether next_node is else-less if in get_return_block
cardigan1008 May 9, 2024
1a3a54c
coverage: Store expression operands as `BcbCounter`
Zalathar Apr 21, 2024
a68bb5e
coverage: Memoize newly-created counter expressions
Zalathar Apr 21, 2024
d01df6f
coverage: Simplify counter expressions using simple algebra
Zalathar May 14, 2024
42119ff
create a feature gate
jdonszelmann May 14, 2024
c811acb
feat: add unit test
cardigan1008 May 16, 2024
9f730e9
Suggest setting lifetime in borrowck error involving types with elide…
estebank May 3, 2024
120049f
Always constrain the return type in lifetime suggestion
estebank May 5, 2024
d1d585d
Account for owning item lifetimes in suggestion and annotate tests as…
estebank May 7, 2024
ee5a157
Run `rustfmt` on modified tests
estebank May 7, 2024
1775e7b
Tweak suggested lifetimes to modify return type instead of `&self` re…
estebank May 7, 2024
cf5702e
Detect when a lifetime is being reused in suggestion
estebank May 17, 2024
95c0e5c
Remove `Rvalue::CheckedBinaryOp`
scottmcm May 16, 2024
d83c65e
Fix clippy
scottmcm May 16, 2024
1d9757c
add todo test for feature gate
jdonszelmann May 20, 2024
7b0fd3b
Migrate `run-make/rustdoc-scrape-examples-whitespace` to `rmake.rs`
GuillaumeGomez May 20, 2024
a4efe6f
add codegen test for issue 120493
jwong101 May 20, 2024
a2e0f10
address nit
pnkfelix May 20, 2024
29c603c
Rollup merge of #124682 - estebank:issue-40990, r=pnkfelix
matthiaskrgr May 20, 2024
ba1bb80
Rollup merge of #124917 - cardigan1008:issue-124819, r=pnkfelix
matthiaskrgr May 20, 2024
e0d9228
Rollup merge of #125106 - Zalathar:expressions, r=davidtwco
matthiaskrgr May 20, 2024
9987e90
Rollup merge of #125173 - scottmcm:never-checked, r=davidtwco
matthiaskrgr May 20, 2024
83cceea
Rollup merge of #125305 - jwong101:120493-codegen-test, r=the8472
matthiaskrgr May 20, 2024
a79737c
Rollup merge of #125314 - jdonszelmann:global-registration-feature-ga…
matthiaskrgr May 20, 2024
1640225
Rollup merge of #125318 - GuillaumeGomez:migrate-rustdoc-examples-whi…
matthiaskrgr May 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_infer/messages.ftl
Original file line number Diff line number Diff line change
@@ -164,7 +164,10 @@ infer_label_bad = {$bad_kind ->
infer_lf_bound_not_satisfied = lifetime bound not satisfied
infer_lifetime_mismatch = lifetime mismatch
infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
infer_lifetime_param_suggestion = consider {$is_reuse ->
[true] reusing
*[false] introducing
} a named lifetime parameter{$is_impl ->
[true] {" "}and update trait if needed
*[false] {""}
}
161 changes: 127 additions & 34 deletions compiler/rustc_infer/src/errors/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use hir::GenericParamKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg,
MultiSpan, SubdiagMessageOp, Subdiagnostic,
};
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::FnRetTy;
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
@@ -355,31 +357,33 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
_f: &F,
) {
let mut mk_suggestion = || {
let (
hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
) = (self.ty_sub, self.ty_sup)
else {
return false;
};

if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
return false;
};

let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
return false;
};

let node = self.tcx.hir_node_by_def_id(anon_reg.def_id);
let is_impl = matches!(&node, hir::Node::ImplItem(_));
let generics = match node {
let (generics, parent_generics) = match node {
hir::Node::Item(&hir::Item {
kind: hir::ItemKind::Fn(_, ref generics, ..),
..
})
| hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
generics,
match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id))
{
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Trait(_, _, ref generics, ..),
..
})
| hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
..
}) => Some(generics),
_ => None,
},
),
_ => return false,
};

@@ -390,24 +394,112 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
.map(|p| p.name.ident().name)
.find(|i| *i != kw::UnderscoreLifetime);
let introduce_new = suggestion_param_name.is_none();

let mut default = "'a".to_string();
if let Some(parent_generics) = parent_generics {
let used: FxHashSet<_> = parent_generics
.params
.iter()
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
.map(|p| p.name.ident().name)
.filter(|i| *i != kw::UnderscoreLifetime)
.map(|l| l.to_string())
.collect();
if let Some(lt) =
('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
{
// We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
// `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
// likely to be an over-constraining lifetime requirement, so we always add a
// lifetime to the `fn`.
default = lt;
}
}
let suggestion_param_name =
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());

debug!(?lifetime_sup.ident.span);
debug!(?lifetime_sub.ident.span);
let make_suggestion = |ident: Ident| {
let sugg = if ident.name == kw::Empty {
format!("{suggestion_param_name}, ")
} else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
format!("{suggestion_param_name} ")
} else {
suggestion_param_name.clone()
};
(ident.span, sugg)
};
let mut suggestions =
vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)];
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);

struct ImplicitLifetimeFinder {
suggestions: Vec<(Span, String)>,
suggestion_param_name: String,
}

impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
let make_suggestion = |ident: Ident| {
if ident.name == kw::Empty && ident.span.is_empty() {
format!("{}, ", self.suggestion_param_name)
} else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
format!("{} ", self.suggestion_param_name)
} else {
self.suggestion_param_name.clone()
}
};
match ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
for segment in path.segments {
if let Some(args) = segment.args {
if args.args.iter().all(|arg| {
matches!(
arg,
hir::GenericArg::Lifetime(lifetime)
if lifetime.ident.name == kw::Empty
)
}) {
self.suggestions.push((
segment.ident.span.shrink_to_hi(),
format!(
"<{}>",
args.args
.iter()
.map(|_| self.suggestion_param_name.clone())
.collect::<Vec<_>>()
.join(", ")
),
));
} else {
for arg in args.args {
if let hir::GenericArg::Lifetime(lifetime) = arg
&& lifetime.is_anonymous()
{
self.suggestions.push((
lifetime.ident.span,
make_suggestion(lifetime.ident),
));
}
}
}
}
}
}
hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
self.suggestions
.push((lifetime.ident.span, make_suggestion(lifetime.ident)));
}
_ => {}
}
walk_ty(self, ty);
}
}
let mut visitor = ImplicitLifetimeFinder {
suggestions: vec![],
suggestion_param_name: suggestion_param_name.clone(),
};
if let Some(fn_decl) = node.fn_decl()
&& let hir::FnRetTy::Return(ty) = fn_decl.output
{
visitor.visit_ty(ty);
}
if visitor.suggestions.is_empty() {
// Do not suggest constraining the `&self` param, but rather the return type.
// If that is wrong (because it is not sufficient), a follow up error will tell the
// user to fix it. This way we lower the chances of *over* constraining, but still
// get the cake of "correctly" contrained in two steps.
visitor.visit_ty(self.ty_sup);
}
visitor.visit_ty(self.ty_sub);
if visitor.suggestions.is_empty() {
return false;
}
if introduce_new {
let new_param_suggestion = if let Some(first) =
generics.params.iter().find(|p| !p.name.ident().span.is_empty())
@@ -417,15 +509,16 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
(generics.span, format!("<{suggestion_param_name}>"))
};

suggestions.push(new_param_suggestion);
visitor.suggestions.push(new_param_suggestion);
}

diag.multipart_suggestion(
diag.multipart_suggestion_verbose(
fluent::infer_lifetime_param_suggestion,
suggestions,
visitor.suggestions,
Applicability::MaybeIncorrect,
);
diag.arg("is_impl", is_impl);
diag.arg("is_reuse", !introduce_new);

true
};
if mk_suggestion() && self.add_note {
4 changes: 2 additions & 2 deletions tests/ui/lifetimes/issue-17728.stderr
Original file line number Diff line number Diff line change
@@ -29,8 +29,8 @@ LL | Some(entry) => Ok(entry),
|
help: consider introducing a named lifetime parameter
|
LL | fn attemptTraverse<'a>(&'a self, room: &'a Room, directionStr: &str) -> Result<&Room, &str> {
| ++++ ++ ++
LL | fn attemptTraverse<'a>(&self, room: &'a Room, directionStr: &str) -> Result<&'a Room, &'a str> {
| ++++ ++ ++ ++

error: aborting due to 2 previous errors

2 changes: 1 addition & 1 deletion tests/ui/lifetimes/issue-90170-elision-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
| | let's call the lifetime of this reference `'1`
| let's call the lifetime of this reference `'2`
|
help: consider introducing a named lifetime parameter
help: consider reusing a named lifetime parameter
|
LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
| ++ ++
Original file line number Diff line number Diff line change
@@ -8,6 +8,11 @@ LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
LL |
LL | if x > y { x } else { y }
| ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
|
help: consider reusing a named lifetime parameter and update trait if needed
|
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
| ++

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//@ run-rustfix
#![allow(dead_code)]
struct Foo {
field: i32,
}

impl Foo {
fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
x
//~^ ERROR lifetime may not live long enough
}
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
//@ run-rustfix
#![allow(dead_code)]
struct Foo {
field: i32
field: i32,
}

impl Foo {
fn foo<'a>(&self, x: &'a i32) -> &i32 {

x
//~^ ERROR lifetime may not live long enough

}

fn foo<'a>(&self, x: &'a i32) -> &i32 {
x
//~^ ERROR lifetime may not live long enough
}
}

fn main() { }
fn main() {}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
error: lifetime may not live long enough
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:8:5
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:9:9
|
LL | fn foo<'a>(&self, x: &'a i32) -> &i32 {
| -- - let's call the lifetime of this reference `'1`
| |
| lifetime `'a` defined here
LL |
LL | x
| ^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
LL | fn foo<'a>(&self, x: &'a i32) -> &i32 {
| -- - let's call the lifetime of this reference `'1`
| |
| lifetime `'a` defined here
LL | x
| ^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
|
help: consider reusing a named lifetime parameter and update trait if needed
|
LL | fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
| ++

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -8,6 +8,11 @@ LL | fn foo<'a>(&self, x: &'a Foo) -> &'a Foo {
LL |
LL | if true { x } else { self }
| ^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
|
help: consider reusing a named lifetime parameter and update trait if needed
|
LL | fn foo<'a>(&'a self, x: &'a Foo) -> &'a Foo {
| ++

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -7,6 +7,11 @@ LL | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
| has type `&mut Vec<Ref<'2, i32>>`
LL | x.push(y);
| ^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
help: consider introducing a named lifetime parameter
|
LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<'a, i32>) {
| ++++ +++ +++

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -7,6 +7,11 @@ LL | fn foo(mut x: Ref, y: Ref) {
| has type `Ref<'_, '2>`
LL | x.b = y.b;
| ^^^^^^^^^ assignment requires that `'1` must outlive `'2`
|
help: consider introducing a named lifetime parameter
|
LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: Ref<'a, 'a>) {
| ++++ ++++++++ ++++++++

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -8,6 +8,11 @@ LL | fn foo(mut x: Ref) {
| has type `Ref<'2, '_>`
LL | x.a = x.b;
| ^^^^^^^^^ assignment requires that `'1` must outlive `'2`
|
help: consider introducing a named lifetime parameter
|
LL | fn foo<'a>(mut x: Ref<'a, 'a>) {
| ++++ ++++++++

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -7,6 +7,11 @@ LL | fn foo(mut x: Vec<Ref>, y: Ref) {
| has type `Vec<Ref<'2>>`
LL | x.push(y);
| ^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
help: consider introducing a named lifetime parameter
|
LL | fn foo<'a>(mut x: Vec<Ref<'a>>, y: Ref<'a>) {
| ++++ ++++ ++++

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -7,6 +7,11 @@ LL | fn foo(mut x: Ref, y: &u32) {
| has type `Ref<'_, '1>`
LL | y = x.b;
| ^^^^^^^ assignment requires that `'1` must outlive `'2`
|
help: consider introducing a named lifetime parameter
|
LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: &'a u32) {
| ++++ ++++++++ ++

error[E0384]: cannot assign to immutable argument `y`
--> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5
Loading