Skip to content

Commit ceac916

Browse files
Validate that uncaptured params are not in hidden type
1 parent 82dae35 commit ceac916

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
@@ -823,16 +823,32 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
823823
let id_args = GenericArgs::identity_for_item(tcx, def_id);
824824
debug!(?id_args);
825825

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

832842
// Convert the type from the function into a type valid outside
833843
// the function, by replacing invalid regions with 'static,
834844
// after producing an error for each of them.
835-
self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors))
845+
self.fold_with(&mut opaque_types::ReverseMapper::new(
846+
tcx,
847+
mapping,
848+
uncaptured_args,
849+
self.span,
850+
ignore_errors,
851+
))
836852
}
837853
}
838854

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::{
87
self, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
98
};
@@ -15,7 +14,12 @@ pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey<TyCtxt<'tcx>>;
1514
/// list to the opaque type's own generics.
1615
pub(super) struct ReverseMapper<'tcx> {
1716
tcx: TyCtxt<'tcx>,
18-
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
17+
18+
mapping: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
19+
20+
/// List of uncaptured args (which are bivariant)
21+
uncaptured_args: FxHashSet<GenericArg<'tcx>>,
22+
1923
/// see call sites to fold_kind_no_missing_regions_error
2024
/// for an explanation of this field.
2125
do_not_error: bool,
@@ -33,11 +37,12 @@ pub(super) struct ReverseMapper<'tcx> {
3337
impl<'tcx> ReverseMapper<'tcx> {
3438
pub(super) fn new(
3539
tcx: TyCtxt<'tcx>,
36-
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
40+
mapping: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
41+
uncaptured_args: FxHashSet<GenericArg<'tcx>>,
3742
span: Span,
3843
ignore_errors: bool,
3944
) -> Self {
40-
Self { tcx, map, do_not_error: false, ignore_errors, span }
45+
Self { tcx, mapping, uncaptured_args, do_not_error: false, ignore_errors, span }
4146
}
4247

4348
fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
@@ -127,25 +132,29 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
127132
}
128133
}
129134

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

148-
ty::Region::new_error(self.cx(), e)
157+
ty::Region::new_error(self.cx(), guar)
149158
}
150159
}
151160
}
@@ -169,27 +178,33 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
169178

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

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

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

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)