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

Stabilize opaque type precise capturing (RFC 3617) #127672

Merged
merged 2 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
gate_all!(postfix_match, "postfix match is experimental");
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
gate_all!(global_registration, "global registration is experimental");
gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");
gate_all!(return_type_notation, "return type notation is experimental");
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ declare_features! (
(accepted, param_attrs, "1.39.0", Some(60406)),
/// Allows parentheses in patterns.
(accepted, pattern_parentheses, "1.31.0", Some(51087)),
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
(accepted, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)),
/// Allows procedural macros in `proc-macro` crates.
(accepted, proc_macro, "1.29.0", Some(38356)),
/// Allows multi-segment paths in attributes and derives.
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,6 @@ declare_features! (
(unstable, patchable_function_entry, "1.81.0", Some(123115)),
/// Allows postfix match `expr.match { ... }`
(unstable, postfix_match, "1.79.0", Some(121618)),
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
(unstable, precise_capturing, "1.79.0", Some(123432)),
/// Allows macro attributes on expressions, statements and non-inline modules.
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2773,7 +2773,6 @@ impl PreciseCapturingArg<'_> {
/// resolution to. Lifetimes don't have this problem, and for them, it's actually
/// kind of detrimental to use a custom node type versus just using [`Lifetime`],
/// since resolve_bound_vars operates on `Lifetime`s.
// FIXME(precise_capturing): Investigate storing this as a path instead?
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct PreciseCapturingNonLifetimeArg {
pub hir_id: HirId,
Expand Down
7 changes: 1 addition & 6 deletions compiler/rustc_lint/src/impl_trait_overcaptures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
/// # #![feature(precise_capturing)]
/// # #![allow(incomplete_features)]
/// # #![deny(impl_trait_overcaptures)]
/// # use std::fmt::Display;
/// let mut x = vec![];
Expand Down Expand Up @@ -56,7 +54,6 @@ declare_lint! {
pub IMPL_TRAIT_OVERCAPTURES,
Allow,
"`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
@feature_gate = precise_capturing;
//@future_incompatible = FutureIncompatibleInfo {
// reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
// reference: "<FIXME>",
Expand All @@ -75,8 +72,7 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
/// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
/// # #![allow(incomplete_features)]
/// # #![feature(lifetime_capture_rules_2024)]
/// # #![deny(impl_trait_redundant_captures)]
/// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }
/// ```
Expand All @@ -90,7 +86,6 @@ declare_lint! {
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
Warn,
"redundant precise-capturing `use<...>` syntax on an `impl Trait`",
@feature_gate = precise_capturing;
}

declare_lint_pass!(
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,6 @@ impl<'a> Parser<'a> {
// lifetimes and ident params (including SelfUpper). These are validated later
// for order, duplication, and whether they actually reference params.
let use_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::precise_capturing, use_span);
let (args, args_span) = self.parse_precise_capturing_args()?;
GenericBound::Use(args, use_span.to(args_span))
} else {
Expand Down
22 changes: 4 additions & 18 deletions compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol};
use rustc_type_ir::Upcast as _;

use super::nice_region_error::find_anon_type;
use super::{nice_region_error, ObligationCauseAsDiagArg};
use crate::error_reporting::infer::ObligationCauseExt as _;
use super::ObligationCauseAsDiagArg;
use crate::error_reporting::infer::ObligationCauseExt;
use crate::error_reporting::TypeErrCtxt;
use crate::errors::{
self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound,
Expand Down Expand Up @@ -1212,22 +1212,8 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
hidden_region,
"",
);
if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
if infcx.tcx.features().precise_capturing {
suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err);
} else {
let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
nice_region_error::suggest_new_region_bound(
tcx,
&mut err,
fn_returns,
hidden_region.to_string(),
None,
format!("captures `{hidden_region}`"),
None,
Some(reg_info.def_id),
)
}
if let Some(_) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err);
}
}
ty::RePlaceholder(_) => {
Expand Down
2 changes: 0 additions & 2 deletions tests/rustdoc-json/impl-trait-precise-capturing.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(precise_capturing)]

//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\"
//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\"
//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\"
Expand Down
1 change: 0 additions & 1 deletion tests/rustdoc/impl-trait-precise-capturing.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//@ aux-build:precise-capturing.rs

#![crate_name = "foo"]
#![feature(precise_capturing)]

extern crate precise_capturing;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ LL | | (a, b)
LL | | }
| |_^
|
help: to declare that `impl Trait<'a>` captures `'b`, you can add an explicit `'b` lifetime bound
help: add a `use<...>` bound to explicitly capture `'b`
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
| ++++
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + use<'a, 'b> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first of all, we now always suggest + use<'a> instead of + 'a to capture a lifetime, since it's strictly more accurate

| +++++++++++++

error: aborting due to 2 previous errors

Expand Down
5 changes: 5 additions & 0 deletions tests/ui/borrowck/alias-liveness/opaque-type-param.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ LL | fn foo<'a>(s: &'a str) -> impl Trait + 'static {
| hidden type `impl Trait + 'static` captures the lifetime `'a` as defined here
LL | bar(s)
| ^^^^^^
|
help: add a `use<...>` bound to explicitly capture `'a`
|
LL | fn foo<'a>(s: &'a str) -> impl Trait + 'static + use<'a> {
| +++++++++

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ LL | fn a(&self) -> impl Iterator {
LL | self.0.iter_mut()
| ^^^^^^^^^^^^^^^^^
|
help: to declare that `impl Iterator` captures `'_`, you can add an explicit `'_` lifetime bound
help: add a `use<...>` bound to explicitly capture `'_`
|
LL | fn a(&self) -> impl Iterator + '_ {
| ++++
LL | fn a(&self) -> impl Iterator + use<'_> {
| +++++++++

error: aborting due to 3 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ LL | fn foo(x: &Vec<i32>) -> impl Sized {
LL | x
| ^
|
help: to declare that `impl Sized` captures `'_`, you can add an explicit `'_` lifetime bound
help: add a `use<...>` bound to explicitly capture `'_`
|
LL | fn foo(x: &Vec<i32>) -> impl Sized + '_ {
| ++++
LL | fn foo(x: &Vec<i32>) -> impl Sized + use<'_> {
| +++++++++

error: aborting due to 1 previous error

Expand Down
4 changes: 0 additions & 4 deletions tests/ui/feature-gates/feature-gate-precise-capturing.rs

This file was deleted.

13 changes: 0 additions & 13 deletions tests/ui/feature-gates/feature-gate-precise-capturing.stderr

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a {
LL | step1::<'a, 'b>()
| ^^^^^^^^^^^^^^^^^
|
help: to declare that `impl Sized + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
help: add a `use<...>` bound to explicitly capture `'b`
|
LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a + 'b {
| ++++
LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a + use<'a, 'b> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could make this suggestion better by removing any + 'a, though I do think we need to be careful about preserving meaning...

| +++++++++++++

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
LL | x
| ^
|
help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
help: add a `use<...>` bound to explicitly capture `'b`
|
LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b {
| ++++
LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + use<'a, 'b, T> {
| ++++++++++++++++

error: aborting due to 1 previous error

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/call_method_ambiguous.next.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0282]: type annotations needed
--> $DIR/call_method_ambiguous.rs:28:13
--> $DIR/call_method_ambiguous.rs:26:13
|
LL | let mut iter = foo(n - 1, m);
| ^^^^^^^^
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/impl-trait/call_method_ambiguous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
//@[next] compile-flags: -Znext-solver
//@[current] run-pass

#![feature(precise_capturing)]

trait Get {
fn get(&mut self) -> u32;
}
Expand Down
12 changes: 6 additions & 6 deletions tests/ui/impl-trait/hidden-lifetimes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
LL | x
| ^
|
help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
help: add a `use<...>` bound to explicitly capture `'b`
|
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b {
| ++++
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + use<'a, 'b, T> {
| ++++++++++++++++

error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds
--> $DIR/hidden-lifetimes.rs:46:5
Expand All @@ -23,10 +23,10 @@ LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl S
LL | x
| ^
|
help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
help: add a `use<...>` bound to explicitly capture `'b`
|
LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b {
| ++++
LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + use<'a, 'b, T> {
| ++++++++++++++++

error: aborting due to 2 previous errors

Expand Down
2 changes: 0 additions & 2 deletions tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(precise_capturing)]

use std::future::Future;
use std::pin::Pin;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0700]: hidden type for `impl Future<Output = i32>` captures lifetime that does not appear in bounds
--> $DIR/cannot-capture-intersection.rs:24:9
--> $DIR/cannot-capture-intersection.rs:22:9
|
LL | fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32> {
| ------------------------- opaque type defined here
Expand Down
18 changes: 9 additions & 9 deletions tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ LL | fn elided(x: &i32) -> impl Copy { x }
| | opaque type defined here
| hidden type `&i32` captures the anonymous lifetime defined here
|
help: to declare that `impl Copy` captures `'_`, you can add an explicit `'_` lifetime bound
help: add a `use<...>` bound to explicitly capture `'_`
|
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ++++
LL | fn elided(x: &i32) -> impl Copy + use<'_> { x }
| +++++++++

error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds
--> $DIR/must_outlive_least_region_or_bound.rs:6:44
Expand All @@ -21,10 +21,10 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| | opaque type defined here
| hidden type `&'a i32` captures the lifetime `'a` as defined here
|
help: to declare that `impl Copy` captures `'a`, you can add an explicit `'a` lifetime bound
help: add a `use<...>` bound to explicitly capture `'a`
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ++++
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + use<'a> { x }
| +++++++++

error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:9:46
Expand Down Expand Up @@ -108,10 +108,10 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
LL | move |_| println!("{}", y)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that `impl Fn(&'a u32)` captures `'b`, you can add an explicit `'b` lifetime bound
help: add a `use<...>` bound to explicitly capture `'b`
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
| ++++
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + use<'a, 'b> {
| +++++++++++++

error[E0310]: the parameter type `T` may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:47:5
Expand Down
10 changes: 3 additions & 7 deletions tests/ui/impl-trait/nested-return-type4.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@ LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized
LL | async move { let _s = s; }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound
help: add a `use<...>` bound to explicitly capture `'s`
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's {
| ++++
help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> {
| ++++
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + use<'s> {
| +++++++++

error: aborting due to 1 previous error

Expand Down
2 changes: 0 additions & 2 deletions tests/ui/impl-trait/precise-capturing/apit.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(precise_capturing)]

fn hello(_: impl Sized + use<>) {}
//~^ ERROR `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/precise-capturing/apit.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
--> $DIR/apit.rs:3:26
--> $DIR/apit.rs:1:26
|
LL | fn hello(_: impl Sized + use<>) {}
| ^^^^^
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(precise_capturing)]

fn no_elided_lt() -> impl Sized + use<'_> {}
//~^ ERROR missing lifetime specifier
//~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_`
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0106]: missing lifetime specifier
--> $DIR/bad-lifetimes.rs:3:39
--> $DIR/bad-lifetimes.rs:1:39
|
LL | fn no_elided_lt() -> impl Sized + use<'_> {}
| ^^ expected named lifetime parameter
Expand All @@ -11,21 +11,21 @@ LL | fn no_elided_lt() -> impl Sized + use<'static> {}
| ~~~~~~~

error[E0261]: use of undeclared lifetime name `'missing`
--> $DIR/bad-lifetimes.rs:10:37
--> $DIR/bad-lifetimes.rs:8:37
|
LL | fn missing_lt() -> impl Sized + use<'missing> {}
| - ^^^^^^^^ undeclared lifetime
| |
| help: consider introducing lifetime `'missing` here: `<'missing>`

error: expected lifetime parameter in `use<...>` precise captures list, found `'_`
--> $DIR/bad-lifetimes.rs:3:39
--> $DIR/bad-lifetimes.rs:1:39
|
LL | fn no_elided_lt() -> impl Sized + use<'_> {}
| ^^

error: expected lifetime parameter in `use<...>` precise captures list, found `'static`
--> $DIR/bad-lifetimes.rs:7:36
--> $DIR/bad-lifetimes.rs:5:36
|
LL | fn static_lt() -> impl Sized + use<'static> {}
| ^^^^^^^
Expand Down
Loading
Loading