From e134c74904bc83c1c92584fad388c20343a8be37 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 10 Dec 2024 20:41:24 +0000 Subject: [PATCH] Rudimentary heuristic to insert parentheses when needed for RPIT overcaptures lint --- compiler/rustc_trait_selection/src/errors.rs | 35 ++++++++++++++++--- .../precise-capturing/overcaptures-2024.fixed | 4 +++ .../precise-capturing/overcaptures-2024.rs | 4 +++ .../overcaptures-2024.stderr | 21 ++++++++++- 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index afac6fc6004c1..68fe90f0de29a 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{Visitor, walk_ty}; -use rustc_hir::{FnRetTy, GenericParamKind}; +use rustc_hir::{FnRetTy, GenericParamKind, Node}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt}; @@ -1888,10 +1888,35 @@ pub fn impl_trait_overcapture_suggestion<'tcx>( .collect::>() .join(", "); - suggs.push(( - tcx.def_span(opaque_def_id).shrink_to_hi(), - format!(" + use<{concatenated_bounds}>"), - )); + let opaque_hir_id = tcx.local_def_id_to_hir_id(opaque_def_id); + // FIXME: This is a bit too conservative, since it ignores parens already written in AST. + let (lparen, rparen) = match tcx + .hir() + .parent_iter(opaque_hir_id) + .nth(1) + .expect("expected ty to have a parent always") + .1 + { + Node::PathSegment(segment) + if segment.args().paren_sugar_output().is_some_and(|ty| ty.hir_id == opaque_hir_id) => + { + ("(", ")") + } + Node::Ty(ty) => match ty.kind { + rustc_hir::TyKind::Ptr(_) | rustc_hir::TyKind::Ref(..) => ("(", ")"), + // FIXME: RPITs are not allowed to be nested in `impl Fn() -> ...`, + // but we eventually could support that, and that would necessitate + // making this more sophisticated. + _ => ("", ""), + }, + _ => ("", ""), + }; + + let rpit_span = tcx.def_span(opaque_def_id); + if !lparen.is_empty() { + suggs.push((rpit_span.shrink_to_lo(), lparen.to_string())); + } + suggs.push((rpit_span.shrink_to_hi(), format!(" + use<{concatenated_bounds}>{rparen}"))); Some(AddPreciseCapturingForOvercapture { suggs, apit_spans }) } diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed index 1eb88c71d54f6..ef8dd055a8aa0 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed @@ -42,4 +42,8 @@ async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +pub fn parens(x: &i32) -> &(impl Clone + use<>) { x } +//~^ ERROR `impl Clone` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs index 6f1ef6a472feb..ce1cfe1246f1d 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs @@ -42,4 +42,8 @@ async fn async_fn<'a>(x: &'a ()) -> impl Sized {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +pub fn parens(x: &i32) -> &impl Clone { x } +//~^ ERROR `impl Clone` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index 63c87cd46c84f..965f8e7b67224 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -146,5 +146,24 @@ help: use the precise capturing `use<...>` syntax to make the captures explicit LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} | +++++++ -error: aborting due to 7 previous errors +error: `impl Clone` will capture more lifetimes than possibly intended in edition 2024 + --> $DIR/overcaptures-2024.rs:45:28 + | +LL | pub fn parens(x: &i32) -> &impl Clone { x } + | ^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: specifically, this lifetime is in scope but not mentioned in the type's bounds + --> $DIR/overcaptures-2024.rs:45:18 + | +LL | pub fn parens(x: &i32) -> &impl Clone { x } + | ^ + = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 +help: use the precise capturing `use<...>` syntax to make the captures explicit + | +LL | pub fn parens(x: &i32) -> &(impl Clone + use<>) { x } + | + ++++++++ + +error: aborting due to 8 previous errors