Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b14523c

Browse files
committedMar 14, 2025
Validate that uncaptured params are not in hidden type
1 parent c3c9ccb commit b14523c

14 files changed

+122
-66
lines changed
 

‎compiler/rustc_middle/messages.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ middle_consider_type_length_limit =
4646
middle_const_eval_non_int =
4747
constant evaluation of enum discriminant resulted in non-integer
4848
49-
middle_const_not_used_in_type_alias =
50-
const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
51-
5249
middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note ->
5350
[true] : {$note}
5451
*[other] {""}

‎compiler/rustc_middle/src/error.rs

-8
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,6 @@ pub(crate) struct RequiresLangItem {
9999
pub name: Symbol,
100100
}
101101

102-
#[derive(Diagnostic)]
103-
#[diag(middle_const_not_used_in_type_alias)]
104-
pub(super) struct ConstNotUsedTraitAlias {
105-
pub ct: String,
106-
#[primary_span]
107-
pub span: Span,
108-
}
109-
110102
pub struct CustomSubdiagnostic<'a> {
111103
pub msg: fn() -> DiagMessage,
112104
pub add_args: Box<dyn FnOnce(&mut dyn FnMut(DiagArgName, DiagArgValue)) + 'a>,

‎compiler/rustc_middle/src/ty/mod.rs

+22-6
Original file line numberDiff line numberDiff line change
@@ -821,16 +821,32 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
821821
let id_args = GenericArgs::identity_for_item(tcx, def_id);
822822
debug!(?id_args);
823823

824-
// This zip may have several times the same lifetime in `args` paired with a different
825-
// lifetime from `id_args`. Simply `collect`ing the iterator is the correct behaviour:
826-
// it will pick the last one, which is the one we introduced in the impl-trait desugaring.
827-
let map = args.iter().zip(id_args).collect();
828-
debug!("map = {:#?}", map);
824+
let mut mapping = FxHashMap::default();
825+
let mut uncaptured_args = FxHashSet::default();
826+
for ((arg, identity_arg), &variance) in
827+
args.iter().zip(id_args).zip(tcx.variances_of(def_id))
828+
{
829+
match variance {
830+
ty::Invariant => {
831+
mapping.insert(arg, identity_arg);
832+
}
833+
ty::Bivariant => {
834+
uncaptured_args.insert(arg);
835+
}
836+
_ => unreachable!(),
837+
}
838+
}
829839

830840
// Convert the type from the function into a type valid outside
831841
// the function, by replacing invalid regions with 'static,
832842
// after producing an error for each of them.
833-
self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors))
843+
self.fold_with(&mut opaque_types::ReverseMapper::new(
844+
tcx,
845+
mapping,
846+
uncaptured_args,
847+
self.span,
848+
ignore_errors,
849+
))
834850
}
835851
}
836852

‎compiler/rustc_middle/src/ty/opaque_types.rs

+64-39
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use rustc_data_structures::fx::FxHashMap;
1+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
22
use rustc_span::Span;
33
use rustc_span::def_id::DefId;
44
use tracing::{debug, instrument, trace};
55

6-
use crate::error::ConstNotUsedTraitAlias;
76
use crate::ty::fold::{TypeFolder, TypeSuperFoldable};
87
use crate::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable};
98

@@ -14,7 +13,12 @@ pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey<TyCtxt<'tcx>>;
1413
/// list to the opaque type's own generics.
1514
pub(super) struct ReverseMapper<'tcx> {
1615
tcx: TyCtxt<'tcx>,
17-
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
16+
17+
mapping: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
18+
19+
/// List of uncaptured args (which are bivariant)
20+
uncaptured_args: FxHashSet<GenericArg<'tcx>>,
21+
1822
/// see call sites to fold_kind_no_missing_regions_error
1923
/// for an explanation of this field.
2024
do_not_error: bool,
@@ -32,11 +36,12 @@ pub(super) struct ReverseMapper<'tcx> {
3236
impl<'tcx> ReverseMapper<'tcx> {
3337
pub(super) fn new(
3438
tcx: TyCtxt<'tcx>,
35-
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
39+
mapping: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
40+
uncaptured_args: FxHashSet<GenericArg<'tcx>>,
3641
span: Span,
3742
ignore_errors: bool,
3843
) -> Self {
39-
Self { tcx, map, do_not_error: false, ignore_errors, span }
44+
Self { tcx, mapping, uncaptured_args, do_not_error: false, ignore_errors, span }
4045
}
4146

4247
fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
@@ -126,25 +131,29 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
126131
}
127132
}
128133

129-
match self.map.get(&r.into()).map(|k| k.unpack()) {
134+
match self.mapping.get(&r.into()).map(|k| k.unpack()) {
130135
Some(GenericArgKind::Lifetime(r1)) => r1,
131136
Some(u) => panic!("region mapped to unexpected kind: {u:?}"),
132-
None if self.do_not_error => self.tcx.lifetimes.re_static,
133137
None => {
134-
let e = self
135-
.tcx
136-
.dcx()
137-
.struct_span_err(self.span, "non-defining opaque type use in defining scope")
138-
.with_span_label(
138+
let guar = if self.uncaptured_args.contains(&r.into()) {
139+
// FIXME(precise_capturing_of_types): Mention `use<>` list
140+
// and add an structured suggestion.
141+
self.tcx.dcx().struct_span_err(
142+
self.span,
143+
format!("hidden type mentions uncaptured lifetime parameter `{r}`"),
144+
)
145+
} else {
146+
self.tcx.dcx().struct_span_err(
139147
self.span,
140148
format!(
141-
"lifetime `{r}` is part of concrete type but not used in \
142-
parameter list of the `impl Trait` type alias"
149+
"lifetime `{r}` is mentioned in hidden type of type alias impl \
150+
trait, but is not declared in its generic args"
143151
),
144152
)
145-
.emit();
153+
}
154+
.emit_unless(self.do_not_error);
146155

147-
ty::Region::new_error(self.cx(), e)
156+
ty::Region::new_error(self.cx(), guar)
148157
}
149158
}
150159
}
@@ -168,27 +177,33 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
168177

169178
ty::Param(param) => {
170179
// Look it up in the generic parameters list.
171-
match self.map.get(&ty.into()).map(|k| k.unpack()) {
180+
match self.mapping.get(&ty.into()).map(|k| k.unpack()) {
172181
// Found it in the generic parameters list; replace with the parameter from the
173182
// opaque type.
174183
Some(GenericArgKind::Type(t1)) => t1,
175184
Some(u) => panic!("type mapped to unexpected kind: {u:?}"),
176185
None => {
177-
debug!(?param, ?self.map);
178-
if !self.ignore_errors {
179-
self.tcx
180-
.dcx()
181-
.struct_span_err(
182-
self.span,
183-
format!(
184-
"type parameter `{ty}` is part of concrete type but not \
185-
used in parameter list for the `impl Trait` type alias"
186-
),
187-
)
188-
.emit();
186+
debug!(?param, ?self.mapping);
187+
let guar = if self.uncaptured_args.contains(&ty.into()) {
188+
// FIXME(precise_capturing_of_types): Mention `use<>` list
189+
// and add an structured suggestion.
190+
self.tcx.dcx().struct_span_err(
191+
self.span,
192+
format!("hidden type mentions uncaptured type parameter `{ty}`"),
193+
)
194+
} else {
195+
self.tcx.dcx().struct_span_err(
196+
self.span,
197+
format!(
198+
"type parameter `{ty}` is mentioned in hidden type of \
199+
type alias impl trait, but is not declared in its generic \
200+
args"
201+
),
202+
)
189203
}
204+
.emit_unless(self.ignore_errors);
190205

191-
Ty::new_misc_error(self.tcx)
206+
Ty::new_error(self.tcx, guar)
192207
}
193208
}
194209
}
@@ -203,20 +218,30 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
203218
match ct.kind() {
204219
ty::ConstKind::Param(..) => {
205220
// Look it up in the generic parameters list.
206-
match self.map.get(&ct.into()).map(|k| k.unpack()) {
221+
match self.mapping.get(&ct.into()).map(|k| k.unpack()) {
207222
// Found it in the generic parameters list, replace with the parameter from the
208223
// opaque type.
209224
Some(GenericArgKind::Const(c1)) => c1,
210225
Some(u) => panic!("const mapped to unexpected kind: {u:?}"),
211226
None => {
212-
let guar = self
213-
.tcx
214-
.dcx()
215-
.create_err(ConstNotUsedTraitAlias {
216-
ct: ct.to_string(),
217-
span: self.span,
218-
})
219-
.emit_unless(self.ignore_errors);
227+
let guar = if self.uncaptured_args.contains(&ct.into()) {
228+
// FIXME(precise_capturing_of_types): Mention `use<>` list
229+
// and add an structured suggestion.
230+
self.tcx.dcx().struct_span_err(
231+
self.span,
232+
format!("hidden type mentions uncaptured const parameter `{ct}`"),
233+
)
234+
} else {
235+
self.tcx.dcx().struct_span_err(
236+
self.span,
237+
format!(
238+
"const parameter `{ct}` is mentioned in hidden type of \
239+
type alias impl trait, but is not declared in its generic \
240+
args"
241+
),
242+
)
243+
}
244+
.emit_unless(self.ignore_errors);
220245

221246
ty::Const::new_error(self.tcx, guar)
222247
}

‎tests/ui/impl-trait/issue-55872-2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ impl<S> Bar for S {
1212
type E = impl std::marker::Send;
1313
fn foo<T>() -> Self::E {
1414
async {}
15-
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
16-
//~| ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
15+
//~^ ERROR type parameter `T` is mentioned
16+
//~| ERROR type parameter `T` is mentioned
1717
}
1818
}
1919

‎tests/ui/impl-trait/issue-55872-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
1+
error: type parameter `T` is mentioned in hidden type of type alias impl trait, but is not declared in its generic args
22
--> $DIR/issue-55872-2.rs:14:9
33
|
44
LL | async {}
55
| ^^^^^^^^
66

7-
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
7+
error: type parameter `T` is mentioned in hidden type of type alias impl trait, but is not declared in its generic args
88
--> $DIR/issue-55872-2.rs:14:9
99
|
1010
LL | async {}

‎tests/ui/impl-trait/issue-55872.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ impl<S> Bar for S {
1111

1212
fn foo<T>() -> Self::E {
1313
|| ()
14-
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
14+
//~^ ERROR type parameter `T` is mentioned
1515
}
1616
}
1717

‎tests/ui/impl-trait/issue-55872.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
1+
error: type parameter `T` is mentioned in hidden type of type alias impl trait, but is not declared in its generic args
22
--> $DIR/issue-55872.rs:13:9
33
|
44
LL | || ()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![feature(precise_capturing_of_types)]
2+
//~^ WARN the feature `precise_capturing_of_types` is incomplete
3+
4+
fn foo<T>(x: T) -> impl Sized + use<> {
5+
x
6+
//~^ ERROR hidden type mentions uncaptured type parameter `T`
7+
}
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: the feature `precise_capturing_of_types` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/of-types-hidden-capture.rs:1:12
3+
|
4+
LL | #![feature(precise_capturing_of_types)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #130043 <https://github.com/rust-lang/rust/issues/130043> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error: hidden type mentions uncaptured type parameter `T`
11+
--> $DIR/of-types-hidden-capture.rs:5:5
12+
|
13+
LL | x
14+
| ^
15+
16+
error: aborting due to 1 previous error; 1 warning emitted
17+

‎tests/ui/type-alias-impl-trait/generic_not_used.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ type WrongGeneric<T: 'static> = impl 'static;
88
#[define_opaque(WrongGeneric)]
99
fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
1010
v
11-
//~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
11+
//~^ ERROR type parameter `V` is mentioned
1212
}

‎tests/ui/type-alias-impl-trait/generic_not_used.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: at least one trait must be specified
44
LL | type WrongGeneric<T: 'static> = impl 'static;
55
| ^^^^^^^^^^^^
66

7-
error: type parameter `V` is part of concrete type but not used in parameter list for the `impl Trait` type alias
7+
error: type parameter `V` is mentioned in hidden type of type alias impl trait, but is not declared in its generic args
88
--> $DIR/generic_not_used.rs:10:5
99
|
1010
LL | v

‎tests/ui/type-alias-impl-trait/issue-53598.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Foo for S2 {
1818

1919
fn foo<T: Debug>(_: T) -> Self::Item {
2020
S::<T>(Default::default())
21-
//~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
21+
//~^ Error type parameter `T` is mentioned
2222
}
2323
}
2424

‎tests/ui/type-alias-impl-trait/issue-53598.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
1+
error: type parameter `T` is mentioned in hidden type of type alias impl trait, but is not declared in its generic args
22
--> $DIR/issue-53598.rs:20:9
33
|
44
LL | S::<T>(Default::default())

0 commit comments

Comments
 (0)
Failed to load comments.