Skip to content

Commit db03071

Browse files
authored
Rollup merge of rust-lang#152444 - ShoyuVanilla:unsized-recursion-limit, r=lcnr
`-Znext-solver` Prevent committing unfulfilled unsized coercion Fixes rust-lang/trait-system-refactor-initiative#266 r? lcnr
2 parents a7385a9 + 891acbd commit db03071

File tree

4 files changed

+84
-3
lines changed

4 files changed

+84
-3
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
644644
.infcx
645645
.visit_proof_tree(
646646
Goal::new(self.tcx, self.param_env, pred),
647-
&mut CoerceVisitor { fcx: self.fcx, span: self.cause.span },
647+
&mut CoerceVisitor { fcx: self.fcx, span: self.cause.span, errored: false },
648648
)
649649
.is_break()
650650
{
@@ -1961,6 +1961,10 @@ impl<'tcx> CoerceMany<'tcx> {
19611961
struct CoerceVisitor<'a, 'tcx> {
19621962
fcx: &'a FnCtxt<'a, 'tcx>,
19631963
span: Span,
1964+
/// Whether the coercion is impossible. If so we sometimes still try to
1965+
/// coerce in these cases to emit better errors. This changes the behavior
1966+
/// when hitting the recursion limit.
1967+
errored: bool,
19641968
}
19651969

19661970
impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> {
@@ -1987,6 +1991,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> {
19871991
// If we prove the `Unsize` or `CoerceUnsized` goal, continue recursing.
19881992
Ok(Certainty::Yes) => ControlFlow::Continue(()),
19891993
Err(NoSolution) => {
1994+
self.errored = true;
19901995
// Even if we find no solution, continue recursing if we find a single candidate
19911996
// for which we're shallowly certain it holds to get the right error source.
19921997
if let [only_candidate] = &goal.candidates()[..]
@@ -2019,4 +2024,15 @@ impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> {
20192024
}
20202025
}
20212026
}
2027+
2028+
fn on_recursion_limit(&mut self) -> Self::Result {
2029+
if self.errored {
2030+
// This prevents accidentally committing unfulfilled unsized coercions while trying to
2031+
// find the error source for diagnostics.
2032+
// See https://github.com/rust-lang/trait-system-refactor-initiative/issues/266.
2033+
ControlFlow::Break(())
2034+
} else {
2035+
ControlFlow::Continue(())
2036+
}
2037+
}
20222038
}

compiler/rustc_trait_selection/src/solve/inspect/analyse.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,9 +443,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
443443
pub(crate) fn visit_with<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
444444
if self.depth < visitor.config().max_depth {
445445
try_visit!(visitor.visit_goal(self));
446+
V::Result::output()
447+
} else {
448+
visitor.on_recursion_limit()
446449
}
447-
448-
V::Result::output()
449450
}
450451
}
451452

@@ -460,6 +461,10 @@ pub trait ProofTreeVisitor<'tcx> {
460461
}
461462

462463
fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> Self::Result;
464+
465+
fn on_recursion_limit(&mut self) -> Self::Result {
466+
Self::Result::output()
467+
}
463468
}
464469

465470
#[extension(pub trait InferCtxtProofTreeExt<'tcx>)]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ check-pass
2+
//@ compile-flags: -Znext-solver
3+
4+
// A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/266.
5+
// Ensure that we do not accidentaly trying unfulfilled unsized coercions due to hitting recursion
6+
// limits while trying to find the right fulfillment error source.
7+
8+
fn argument_coercion<U>(_: &U) {}
9+
10+
pub fn test() {
11+
argument_coercion(&{
12+
Nested(0.0, 0.0)
13+
.add(0.0)
14+
.add(0.0)
15+
.add(0.0)
16+
.add(0.0)
17+
.add(0.0)
18+
.add(0.0)
19+
.add(0.0)
20+
.add(0.0)
21+
.add(0.0)
22+
.add(0.0)
23+
.add(0.0)
24+
});
25+
}
26+
27+
struct Nested<T, R>(T, R);
28+
29+
impl<T, R> Nested<T, R> {
30+
fn add<U>(self, value: U) -> Nested<U, Nested<T, R>> {
31+
Nested(value, self)
32+
}
33+
}
34+
35+
fn main() {}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ check-pass
2+
//@ compile-flags: -Znext-solver
3+
4+
// A test to ensure that unsized coercion is not aborted when visiting a nested goal that
5+
// exceeds the recursion limit and evaluates to `Certainty::Maybe`.
6+
// See https://github.com/rust-lang/rust/pull/152444.
7+
8+
#![allow(warnings)]
9+
10+
struct W<T: ?Sized>(T);
11+
type Four<T: ?Sized> = W<W<W<W<T>>>>;
12+
type Sixteen<T: ?Sized> = Four<Four<Four<Four<T>>>>;
13+
14+
fn ret<T>(x: T) -> Sixteen<T> {
15+
todo!();
16+
}
17+
18+
fn please_coerce() {
19+
let mut y = Default::default();
20+
let x = ret(y);
21+
let _: &Sixteen<dyn Send> = &x;
22+
y = 1u32;
23+
}
24+
25+
fn main() {}

0 commit comments

Comments
 (0)