Skip to content

Commit f1acf6a

Browse files
Don't infer closure signatures with late-bound type vars
1 parent 5833d54 commit f1acf6a

File tree

9 files changed

+185
-9
lines changed

9 files changed

+185
-9
lines changed

compiler/rustc_hir_typeck/src/closure.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
244244
}
245245
}
246246
}
247-
if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
247+
// FIXME(non_lifetime_binder): Don't infer a signature with late-bound ty/ct vars
248+
if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue()
249+
&& !inferred_sig.has_non_region_late_bound()
250+
{
248251
expected_sig = inferred_sig;
249252
}
250253
}

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2735,6 +2735,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
27352735
| (ty::Infer(ty::InferTy::TyVar(_)), _)
27362736
| (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a),
27372737
(ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch),
2738+
(ty::Bound(..), _) | (_, ty::Bound(..)) => Err(TypeError::Mismatch),
27382739
_ => relate::super_relate_tys(self, a, b),
27392740
}
27402741
}

compiler/rustc_middle/src/ty/visit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
8383
| TypeFlags::HAS_CT_PLACEHOLDER,
8484
)
8585
}
86+
/// True if there are any non-region placeholders
87+
fn has_non_region_placeholders(&self) -> bool {
88+
self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER)
89+
}
8690
fn needs_subst(&self) -> bool {
8791
self.has_type_flags(TypeFlags::NEEDS_SUBST)
8892
}

compiler/rustc_trait_selection/src/solve/project_goals.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,13 +308,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
308308
) -> QueryResult<'tcx> {
309309
let tcx = ecx.tcx();
310310
let Some(tupled_inputs_and_output) =
311-
structural_traits::extract_tupled_inputs_and_output_from_callable(
312-
tcx,
313-
goal.predicate.self_ty(),
314-
goal_kind,
315-
)? else {
316-
return ecx.make_canonical_response(Certainty::AMBIGUOUS);
317-
};
311+
structural_traits::extract_tupled_inputs_and_output_from_callable(
312+
tcx,
313+
goal.predicate.self_ty(),
314+
goal_kind,
315+
)? else {
316+
return ecx.make_canonical_response(Certainty::AMBIGUOUS);
317+
};
318+
319+
// FIXME(non_lifetime_binders): Higher-ranked Fn trait candidates are not (yet) supported.
320+
// Make sure that the inputs/output don't capture any placeholder types.
321+
if (goal.predicate.projection_ty.substs[1], goal.predicate.term)
322+
.has_non_region_placeholders()
323+
{
324+
return Err(NoSolution);
325+
}
326+
318327
let output_is_sized_pred = tupled_inputs_and_output
319328
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
320329

compiler/rustc_trait_selection/src/solve/trait_goals.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
215215
goal_kind: ty::ClosureKind,
216216
) -> QueryResult<'tcx> {
217217
let tcx = ecx.tcx();
218+
219+
// FIXME(non_lifetime_binders): Higher-ranked Fn trait candidates are not (yet) supported.
220+
// Check that the inputs don't capture any placeholder types.
221+
if goal.predicate.trait_ref.substs[1].has_non_region_placeholders() {
222+
return Err(NoSolution);
223+
}
224+
218225
let Some(tupled_inputs_and_output) =
219226
structural_traits::extract_tupled_inputs_and_output_from_callable(
220227
tcx,

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
760760
};
761761

762762
let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
763-
let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
763+
764+
// FIXME(non_lifetime_binders): Perform the equivalent of a "leak check" here.
765+
let mut nested = self.infcx.commit_if_ok(|_| {
766+
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
767+
768+
if self
769+
.infcx
770+
.resolve_vars_if_possible(substs.as_closure().sig())
771+
.has_non_region_placeholders()
772+
{
773+
return Err(SelectionError::Unimplemented);
774+
}
775+
776+
Ok(nested)
777+
})?;
764778

765779
debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
766780

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/closure-infer.rs:4:12
3+
|
4+
LL | #![feature(non_lifetime_binders)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0277]: expected a `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
11+
--> $DIR/closure-infer.rs:12:15
12+
|
13+
LL | fn take2() -> impl for<T> Fn(T) -> T {
14+
| ^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
15+
|
16+
= help: the trait `Fn<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
17+
18+
error[E0277]: expected a `FnOnce<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
19+
--> $DIR/closure-infer.rs:12:15
20+
|
21+
LL | fn take2() -> impl for<T> Fn(T) -> T {
22+
| ^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
23+
|
24+
= help: the trait `FnOnce<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
25+
26+
error[E0277]: expected a `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
27+
--> $DIR/closure-infer.rs:20:10
28+
|
29+
LL | take(|x| x)
30+
| ---- ^^^^^ expected an `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
31+
| |
32+
| required by a bound introduced by this call
33+
|
34+
= help: the trait `Fn<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
35+
note: required by a bound in `take`
36+
--> $DIR/closure-infer.rs:7:18
37+
|
38+
LL | fn take(id: impl for<T> Fn(T) -> T) {
39+
| ^^^^^^^^^^^^^^^^^ required by this bound in `take`
40+
41+
error[E0277]: expected a `FnOnce<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
42+
--> $DIR/closure-infer.rs:20:10
43+
|
44+
LL | take(|x| x)
45+
| ---- ^^^^^ expected an `FnOnce<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
46+
| |
47+
| required by a bound introduced by this call
48+
|
49+
= help: the trait `FnOnce<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
50+
note: required by a bound in `take`
51+
--> $DIR/closure-infer.rs:7:34
52+
|
53+
LL | fn take(id: impl for<T> Fn(T) -> T) {
54+
| ^ required by this bound in `take`
55+
56+
error: aborting due to 4 previous errors; 1 warning emitted
57+
58+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/closure-infer.rs:4:12
3+
|
4+
LL | #![feature(non_lifetime_binders)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0277]: expected a `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
11+
--> $DIR/closure-infer.rs:12:15
12+
|
13+
LL | fn take2() -> impl for<T> Fn(T) -> T {
14+
| ^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
15+
|
16+
= help: the trait `Fn<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:16:5: 16:8]`
17+
18+
error[E0271]: type mismatch resolving `<[[email protected]:16:5] as FnOnce<(T,)>>::Output == T`
19+
--> $DIR/closure-infer.rs:12:15
20+
|
21+
LL | fn take2() -> impl for<T> Fn(T) -> T {
22+
| ^^^^^^^^^^^^^^^^^^^^^^ types differ
23+
24+
error[E0277]: expected a `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
25+
--> $DIR/closure-infer.rs:20:10
26+
|
27+
LL | take(|x| x)
28+
| ---- ^^^^^ expected an `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
29+
| |
30+
| required by a bound introduced by this call
31+
|
32+
= help: the trait `Fn<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:20:10: 20:13]`
33+
note: required by a bound in `take`
34+
--> $DIR/closure-infer.rs:7:18
35+
|
36+
LL | fn take(id: impl for<T> Fn(T) -> T) {
37+
| ^^^^^^^^^^^^^^^^^ required by this bound in `take`
38+
39+
error[E0271]: type mismatch resolving `<[[email protected]:20:10] as FnOnce<(T,)>>::Output == T`
40+
--> $DIR/closure-infer.rs:20:10
41+
|
42+
LL | take(|x| x)
43+
| ---- ^^^^^ types differ
44+
| |
45+
| required by a bound introduced by this call
46+
|
47+
note: required by a bound in `take`
48+
--> $DIR/closure-infer.rs:7:34
49+
|
50+
LL | fn take(id: impl for<T> Fn(T) -> T) {
51+
| ^ required by this bound in `take`
52+
53+
error: aborting due to 4 previous errors; 1 warning emitted
54+
55+
Some errors have detailed explanations: E0271, E0277.
56+
For more information about an error, try `rustc --explain E0271`.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// revisions: classic next
2+
//[next] compile-flags: -Ztrait-solver=next
3+
4+
#![feature(non_lifetime_binders)]
5+
//~^ WARNING the feature `non_lifetime_binders` is incomplete
6+
7+
fn take(id: impl for<T> Fn(T) -> T) {
8+
id(0);
9+
id("");
10+
}
11+
12+
fn take2() -> impl for<T> Fn(T) -> T {
13+
//~^ ERROR expected a `Fn<(T,)>` closure, found
14+
//[classic]~| ERROR expected a `FnOnce<(T,)>` closure, found
15+
//[next]~| ERROR type mismatch resolving
16+
|x| x
17+
}
18+
19+
fn main() {
20+
take(|x| x)
21+
//~^ ERROR expected a `Fn<(T,)>` closure, found
22+
//[classic]~| ERROR expected a `FnOnce<(T,)>` closure, found
23+
//[next]~| ERROR type mismatch resolving
24+
}

0 commit comments

Comments
 (0)