Skip to content

Commit 8e70079

Browse files
committed
Implement partial capturing of types in use<...>
1 parent 73c0ae6 commit 8e70079

File tree

5 files changed

+144
-5
lines changed

5 files changed

+144
-5
lines changed

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,9 @@ hir_analysis_param_in_ty_of_assoc_const_binding =
417417
*[normal] the {$param_def_kind} `{$param_name}` is defined here
418418
}
419419
420-
hir_analysis_param_not_captured = `impl Trait` must mention all {$kind} parameters in scope in `use<...>`
420+
hir_analysis_param_not_captured = `impl Trait` must mention all used {$kind} parameters in scope in `use<...>`
421421
.label = {$kind} parameter is implicitly captured by this `impl Trait`
422-
.note = currently, all {$kind} parameters are required to be mentioned in the precise captures list
422+
.suggestion = add `{$name}` in the capture list
423423
424424
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
425425
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
@@ -481,7 +481,6 @@ hir_analysis_self_in_impl_self =
481481
482482
hir_analysis_self_ty_not_captured = `impl Trait` must mention the `Self` type of the trait in `use<...>`
483483
.label = `Self` type parameter is implicitly captured by this `impl Trait`
484-
.note = currently, all type parameters are required to be mentioned in the precise captures list
485484
486485
hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code
487486
.help = add `#![feature(simd_ffi)]` to the crate attributes to enable

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,29 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
660660
}
661661
}
662662

663+
// Collect all the param used by the opaque type into `expected_captures`, so that we
664+
// can check they must be in the capture list.
665+
let mut used_params = UnordSet::default();
666+
let generics = tcx.generics_of(opaque_def_id);
667+
for generic_arg in tcx.type_of(opaque_def_id).skip_binder().walk() {
668+
match generic_arg.unpack() {
669+
ty::GenericArgKind::Type(ty_arg)
670+
if let &ty::Param(ty::ParamTy { index, .. }) = ty_arg.kind() =>
671+
{
672+
used_params.insert(generics.param_at(index as usize, tcx).def_id);
673+
}
674+
ty::GenericArgKind::Const(const_arg)
675+
if let ty::ConstKind::Param(ty::ParamConst { index, .. }) = const_arg.kind() =>
676+
{
677+
used_params.insert(generics.param_at(index as usize, tcx).def_id);
678+
}
679+
// lifetime params are checked separately
680+
ty::GenericArgKind::Lifetime(_)
681+
| ty::GenericArgKind::Type(_)
682+
| ty::GenericArgKind::Const(_) => {}
683+
}
684+
}
685+
663686
let variances = tcx.variances_of(opaque_def_id);
664687
let mut def_id = Some(opaque_def_id.to_def_id());
665688
while let Some(generics) = def_id {
@@ -682,6 +705,11 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
682705
continue;
683706
}
684707

708+
// If a param is not used by the opaque type, then it need not be captured.
709+
if !used_params.contains(&param.def_id) {
710+
continue;
711+
}
712+
685713
match param.kind {
686714
ty::GenericParamDefKind::Lifetime => {
687715
let use_span = tcx.def_span(param.def_id);

compiler/rustc_hir_analysis/src/errors/precise_captures.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use rustc_span::{Span, Symbol};
44

55
#[derive(Diagnostic)]
66
#[diag(hir_analysis_param_not_captured)]
7-
#[note]
87
pub(crate) struct ParamNotCaptured {
98
#[primary_span]
109
pub opaque_span: Span,
@@ -15,7 +14,6 @@ pub(crate) struct ParamNotCaptured {
1514

1615
#[derive(Diagnostic)]
1716
#[diag(hir_analysis_self_ty_not_captured)]
18-
#[note]
1917
pub(crate) struct SelfTyNotCaptured {
2018
#[primary_span]
2119
pub opaque_span: Span,
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// See #130043 and #130031
2+
3+
fn main() {
4+
let mut data = [1, 2, 3];
5+
let mut i = indices(&data);
6+
data = [4, 5, 6];
7+
i.next();
8+
9+
let mut i = enumerated_opaque(&data);
10+
i.next();
11+
12+
let mut i = enumerated(&data);
13+
i.next();
14+
15+
let mut i = enumerated_lt(&data);
16+
i.next();
17+
18+
let mut i = enumerated_arr(data);
19+
i.next();
20+
}
21+
22+
// No lifetime or type params captured
23+
fn indices<T>(slice: &[T]) -> impl Iterator<Item = usize> + use<> {
24+
0..slice.len()
25+
}
26+
27+
// `'_` and `T` are captured
28+
fn enumerated_opaque<T>(slice: &[T]) -> impl Iterator + use<> {
29+
slice.iter().enumerate()
30+
//~^ ERROR hidden type for `impl Iterator` captures lifetime that does not appear in bounds
31+
}
32+
33+
// `'_` and `T` are captured
34+
fn enumerated_opaque_lt<T>(slice: &[T]) -> impl Iterator + use<'_> {
35+
//~^ ERROR `impl Trait` must mention all used type parameters in scope in `use<...>`
36+
slice.iter().enumerate()
37+
}
38+
39+
// `'_` and `T` are captured
40+
fn enumerated<T>(slice: &[T]) -> impl Iterator<Item = (usize, &T)> + use<> {
41+
//~^ ERROR `impl Trait` must mention all used type parameters in scope in `use<...>`
42+
slice.iter().enumerate()
43+
}
44+
45+
// `'_` and `T` are captured
46+
fn enumerated_lt<T>(slice: &[T]) -> impl Iterator<Item = (usize, &T)> + use<'_> {
47+
//~^ ERROR `impl Trait` must mention all used type parameters in scope in `use<...>`
48+
slice.iter().enumerate()
49+
}
50+
51+
// `T` and `N` are captured
52+
fn enumerated_arr<T, const N: usize>(arr: [T; N]) -> impl Iterator<Item = (usize, T)> + use<> {
53+
//~^ ERROR `impl Trait` must mention all used type parameters in scope in `use<...>`
54+
//~| ERROR `impl Trait` must mention all used const parameters in scope in `use<...>`
55+
<[T; N]>::into_iter(arr).enumerate()
56+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds
2+
--> $DIR/partial-capture.rs:29:5
3+
|
4+
LL | fn enumerated_opaque<T>(slice: &[T]) -> impl Iterator + use<> {
5+
| ---- --------------------- opaque type defined here
6+
| |
7+
| hidden type `Enumerate<std::slice::Iter<'_, T>>` captures the anonymous lifetime defined here
8+
LL | slice.iter().enumerate()
9+
| ^^^^^^^^^^^^^^^^^^^^^^^^
10+
|
11+
help: add `'_` to the `use<...>` bound to explicitly capture it
12+
|
13+
LL | fn enumerated_opaque<T>(slice: &[T]) -> impl Iterator + use<'_> {
14+
| ++
15+
16+
error: `impl Trait` must mention all used type parameters in scope in `use<...>`
17+
--> $DIR/partial-capture.rs:34:44
18+
|
19+
LL | fn enumerated_opaque_lt<T>(slice: &[T]) -> impl Iterator + use<'_> {
20+
| - ^^^^^^^^^^^^^^^^^^^^^^^
21+
| |
22+
| type parameter is implicitly captured by this `impl Trait`
23+
24+
error: `impl Trait` must mention all used type parameters in scope in `use<...>`
25+
--> $DIR/partial-capture.rs:40:34
26+
|
27+
LL | fn enumerated<T>(slice: &[T]) -> impl Iterator<Item = (usize, &T)> + use<> {
28+
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29+
| |
30+
| type parameter is implicitly captured by this `impl Trait`
31+
32+
error: `impl Trait` must mention all used type parameters in scope in `use<...>`
33+
--> $DIR/partial-capture.rs:46:37
34+
|
35+
LL | fn enumerated_lt<T>(slice: &[T]) -> impl Iterator<Item = (usize, &T)> + use<'_> {
36+
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
37+
| |
38+
| type parameter is implicitly captured by this `impl Trait`
39+
40+
error: `impl Trait` must mention all used type parameters in scope in `use<...>`
41+
--> $DIR/partial-capture.rs:52:54
42+
|
43+
LL | fn enumerated_arr<T, const N: usize>(arr: [T; N]) -> impl Iterator<Item = (usize, T)> + use<> {
44+
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45+
| |
46+
| type parameter is implicitly captured by this `impl Trait`
47+
48+
error: `impl Trait` must mention all used const parameters in scope in `use<...>`
49+
--> $DIR/partial-capture.rs:52:54
50+
|
51+
LL | fn enumerated_arr<T, const N: usize>(arr: [T; N]) -> impl Iterator<Item = (usize, T)> + use<> {
52+
| -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
53+
| |
54+
| const parameter is implicitly captured by this `impl Trait`
55+
56+
error: aborting due to 6 previous errors
57+
58+
For more information about this error, try `rustc --explain E0700`.

0 commit comments

Comments
 (0)