Skip to content

Commit 0900c2f

Browse files
committed
Normalize obligations for closure confirmation
1 parent ad02dc4 commit 0900c2f

18 files changed

+349
-79
lines changed

compiler/rustc_middle/src/ty/print/pretty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,7 @@ pub trait PrettyPrinter<'tcx>:
721721
p!(print_def_path(did, substs));
722722
if !substs.as_closure().is_valid() {
723723
p!(" closure_substs=(unavailable)");
724+
p!(write(" substs={:?}", substs));
724725
} else {
725726
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
726727
p!(

compiler/rustc_trait_selection/src/traits/project.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -1747,7 +1747,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
17471747
ty: ret_type,
17481748
});
17491749

1750-
confirm_param_env_candidate(selcx, obligation, predicate, false)
1750+
confirm_param_env_candidate(selcx, obligation, predicate, true)
17511751
}
17521752

17531753
fn confirm_param_env_candidate<'cx, 'tcx>(
@@ -1767,8 +1767,18 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
17671767
);
17681768

17691769
let cache_projection = cache_entry.projection_ty;
1770-
let obligation_projection = obligation.predicate;
17711770
let mut nested_obligations = Vec::new();
1771+
let obligation_projection = obligation.predicate;
1772+
let obligation_projection = ensure_sufficient_stack(|| {
1773+
normalize_with_depth_to(
1774+
selcx,
1775+
obligation.param_env,
1776+
obligation.cause.clone(),
1777+
obligation.recursion_depth + 1,
1778+
obligation_projection,
1779+
&mut nested_obligations,
1780+
)
1781+
});
17721782
let cache_projection = if potentially_unnormalized_candidate {
17731783
ensure_sufficient_stack(|| {
17741784
normalize_with_depth_to(
@@ -1784,6 +1794,8 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
17841794
cache_projection
17851795
};
17861796

1797+
debug!(?cache_projection, ?obligation_projection);
1798+
17871799
match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
17881800
Ok(InferOk { value: _, obligations }) => {
17891801
nested_obligations.extend(obligations);

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

+24-10
Original file line numberDiff line numberDiff line change
@@ -619,23 +619,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
619619
_ => bug!("closure candidate for non-closure {:?}", obligation),
620620
};
621621

622+
let obligation_predicate = obligation.predicate.to_poly_trait_ref();
623+
let Normalized { value: obligation_predicate, mut obligations } =
624+
ensure_sufficient_stack(|| {
625+
normalize_with_depth(
626+
self,
627+
obligation.param_env,
628+
obligation.cause.clone(),
629+
obligation.recursion_depth + 1,
630+
obligation_predicate,
631+
)
632+
});
633+
622634
let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
623-
let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
624-
normalize_with_depth(
625-
self,
626-
obligation.param_env,
627-
obligation.cause.clone(),
628-
obligation.recursion_depth + 1,
629-
trait_ref,
630-
)
631-
});
635+
let Normalized { value: trait_ref, obligations: trait_ref_obligations } =
636+
ensure_sufficient_stack(|| {
637+
normalize_with_depth(
638+
self,
639+
obligation.param_env,
640+
obligation.cause.clone(),
641+
obligation.recursion_depth + 1,
642+
trait_ref,
643+
)
644+
});
632645

633646
debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations");
634647

648+
obligations.extend(trait_ref_obligations);
635649
obligations.extend(self.confirm_poly_trait_refs(
636650
obligation.cause.clone(),
637651
obligation.param_env,
638-
obligation.predicate.to_poly_trait_ref(),
652+
obligation_predicate,
639653
trait_ref,
640654
)?);
641655

src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | let c1 : () = c;
99
| expected due to this
1010
|
1111
= note: expected unit type `()`
12-
found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable)]`
12+
found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#27t, extern "rust-call" fn(()), _#28t]]`
1313
help: use parentheses to call this closure
1414
|
1515
LL | let c1 : () = c();

src/test/ui/closures/print/closure-print-generic-verbose-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | let c1 : () = c;
99
| expected due to this
1010
|
1111
= note: expected unit type `()`
12-
found closure `[f<T>::{closure#0} closure_substs=(unavailable)]`
12+
found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#27t, extern "rust-call" fn(()), _#28t]]`
1313
help: use parentheses to call this closure
1414
|
1515
LL | let c1 : () = c();

src/test/ui/closures/print/closure-print-verbose.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
77
| expected due to this
88
|
99
= note: expected fn pointer `fn(u8) -> u8`
10-
found closure `[main::{closure#0} closure_substs=(unavailable)]`
10+
found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, _#6t]]`
1111
note: closures can only be coerced to `fn` types if they do not capture any variables
1212
--> $DIR/closure-print-verbose.rs:10:39
1313
|

src/test/ui/issues/issue-44005.rs renamed to src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// check-pass
2+
13
pub trait Foo<'a> {
24
type Bar;
35
fn foo(&'a self) -> Self::Bar;
@@ -24,7 +26,6 @@ pub fn catalyst(x: &i32) {
2426

2527
pub fn broken<F: Fn(&i32)>(x: &i32, f: F) {
2628
uncallable(x, |y| f(y));
27-
//~^ type mismatch
2829
}
2930

3031
fn main() {}

src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ where P: Execute + 'static {
7777
}
7878

7979
fn main() {
80-
task(annotate( //~ type mismatch
80+
task(annotate(
8181
//~^ the size
8282
//~^^ the trait bound
8383
Annotate::<RefMutFamily<usize>>::new(),

src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr

+2-21
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,3 @@
1-
error[E0631]: type mismatch in closure arguments
2-
--> $DIR/issue-62529-1.rs:80:10
3-
|
4-
LL | task(annotate(
5-
| ^^^^^^^^ expected signature of `for<'r> fn(<RefMutFamily<usize> as FamilyLt<'r>>::Out) -> _`
6-
...
7-
LL | |value: &mut usize| {
8-
| ------------------- found signature of `for<'r> fn(&'r mut usize) -> _`
9-
|
10-
note: required by a bound in `annotate`
11-
--> $DIR/issue-62529-1.rs:44:8
12-
|
13-
LL | fn annotate<F, Q>(_q: Annotate<Q>, func: F) -> impl Execute + 'static
14-
| -------- required by a bound in this
15-
LL | where
16-
LL | F: for<'r> FnOnce(<<Q as Inject>::I as FamilyLt<'r>>::Out) + 'static,
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `annotate`
18-
191
error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time
202
--> $DIR/issue-62529-1.rs:80:10
213
|
@@ -61,7 +43,6 @@ LL | fn task<P>(processor: P) -> Task
6143
LL | where P: Execute + 'static {
6244
| ^^^^^^^ required by this bound in `task`
6345

64-
error: aborting due to 3 previous errors
46+
error: aborting due to 2 previous errors
6547

66-
Some errors have detailed explanations: E0277, E0631.
67-
For more information about an error, try `rustc --explain E0277`.
48+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// check-pass
2+
13
pub trait MyTrait<'a> {
24
type Output: 'a;
35
fn gimme_value(&self) -> Self::Output;
@@ -23,7 +25,7 @@ where
2325

2426
fn main() {
2527
let struc = MyStruct;
26-
meow(struc, |foo| { //~ type mismatch
28+
meow(struc, |foo| {
2729
println!("{:?}", foo);
2830
})
2931
}

src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.stderr

-20
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// check-pass
2+
3+
use std::marker::PhantomData;
4+
5+
trait A<'a> {
6+
type B;
7+
fn b(self) -> Self::B;
8+
}
9+
10+
struct T;
11+
struct S<'a>(PhantomData<&'a ()>);
12+
13+
impl<'a> A<'a> for T {
14+
type B = S<'a>;
15+
fn b(self) -> Self::B {
16+
S(PhantomData)
17+
}
18+
}
19+
20+
fn s<TT, F>(t: TT, f: F)
21+
where
22+
TT: for<'a> A<'a>,
23+
F: for<'a> FnOnce(<TT as A<'a>>::B)
24+
{
25+
f(t.b());
26+
}
27+
28+
fn main() {
29+
s(T, |_| {});
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
error: implementation of `Parser` is not general enough
2+
--> $DIR/normalization-under-binders-2.rs:53:5
3+
|
4+
LL | foo(bar, "string", |s| s.len() == 5);
5+
| ^^^ implementation of `Parser` is not general enough
6+
|
7+
= note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
8+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
9+
10+
error: implementation of `Parser` is not general enough
11+
--> $DIR/normalization-under-binders-2.rs:53:5
12+
|
13+
LL | foo(bar, "string", |s| s.len() == 5);
14+
| ^^^ implementation of `Parser` is not general enough
15+
|
16+
= note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
17+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
18+
19+
error: implementation of `Parser` is not general enough
20+
--> $DIR/normalization-under-binders-2.rs:53:5
21+
|
22+
LL | foo(bar, "string", |s| s.len() == 5);
23+
| ^^^ implementation of `Parser` is not general enough
24+
|
25+
= note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
26+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
27+
28+
error: implementation of `Parser` is not general enough
29+
--> $DIR/normalization-under-binders-2.rs:53:5
30+
|
31+
LL | foo(bar, "string", |s| s.len() == 5);
32+
| ^^^ implementation of `Parser` is not general enough
33+
|
34+
= note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
35+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
36+
37+
error: implementation of `Parser` is not general enough
38+
--> $DIR/normalization-under-binders-2.rs:53:5
39+
|
40+
LL | foo(bar, "string", |s| s.len() == 5);
41+
| ^^^ implementation of `Parser` is not general enough
42+
|
43+
= note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
44+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
45+
46+
error: implementation of `Parser` is not general enough
47+
--> $DIR/normalization-under-binders-2.rs:59:5
48+
|
49+
LL | foo(baz, "string", |s| s.0.len() == 5);
50+
| ^^^ implementation of `Parser` is not general enough
51+
|
52+
= note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
53+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
54+
55+
error: implementation of `Parser` is not general enough
56+
--> $DIR/normalization-under-binders-2.rs:59:5
57+
|
58+
LL | foo(baz, "string", |s| s.0.len() == 5);
59+
| ^^^ implementation of `Parser` is not general enough
60+
|
61+
= note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
62+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
63+
64+
error: implementation of `Parser` is not general enough
65+
--> $DIR/normalization-under-binders-2.rs:59:5
66+
|
67+
LL | foo(baz, "string", |s| s.0.len() == 5);
68+
| ^^^ implementation of `Parser` is not general enough
69+
|
70+
= note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
71+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
72+
73+
error: implementation of `Parser` is not general enough
74+
--> $DIR/normalization-under-binders-2.rs:59:5
75+
|
76+
LL | foo(baz, "string", |s| s.0.len() == 5);
77+
| ^^^ implementation of `Parser` is not general enough
78+
|
79+
= note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
80+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
81+
82+
error: implementation of `Parser` is not general enough
83+
--> $DIR/normalization-under-binders-2.rs:59:5
84+
|
85+
LL | foo(baz, "string", |s| s.0.len() == 5);
86+
| ^^^ implementation of `Parser` is not general enough
87+
|
88+
= note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
89+
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
90+
91+
error: aborting due to 10 previous errors
92+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// ignore-compare-mode-nll
2+
// fails in migrate, passes in nll
3+
4+
trait Parser<'s> {
5+
type Output;
6+
7+
fn call(&self, input: &'s str) -> (&'s str, Self::Output);
8+
}
9+
10+
impl<'s, F, T> Parser<'s> for F
11+
where F: Fn(&'s str) -> (&'s str, T) {
12+
type Output = T;
13+
fn call(&self, input: &'s str) -> (&'s str, T) {
14+
self(input)
15+
}
16+
}
17+
18+
fn foo<F1, F2>(
19+
f1: F1,
20+
base: &'static str,
21+
f2: F2
22+
)
23+
where
24+
F1: for<'a> Parser<'a>,
25+
F2: FnOnce(&<F1 as Parser>::Output) -> bool
26+
{
27+
let s: String = base.to_owned();
28+
let str_ref = s.as_ref();
29+
let (remaining, produced) = f1.call(str_ref);
30+
assert!(f2(&produced));
31+
assert_eq!(remaining.len(), 0);
32+
}
33+
34+
struct Wrapper<'a>(&'a str);
35+
36+
fn main() {
37+
fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
38+
(&s[..1], &s[..])
39+
}
40+
41+
fn baz<'a>(s: &'a str) -> (&'a str, Wrapper<'a>) {
42+
(&s[..1], Wrapper(&s[..]))
43+
}
44+
45+
foo(bar, "string", |s| s.len() == 5);
46+
//~^ ERROR implementation of `Parser` is not general enough
47+
//~| ERROR implementation of `Parser` is not general enough
48+
//~| ERROR implementation of `Parser` is not general enough
49+
//~| ERROR implementation of `Parser` is not general enough
50+
//~| ERROR implementation of `Parser` is not general enough
51+
foo(baz, "string", |s| s.0.len() == 5);
52+
//~^ ERROR implementation of `Parser` is not general enough
53+
//~| ERROR implementation of `Parser` is not general enough
54+
//~| ERROR implementation of `Parser` is not general enough
55+
//~| ERROR implementation of `Parser` is not general enough
56+
//~| ERROR implementation of `Parser` is not general enough
57+
}

0 commit comments

Comments
 (0)