Skip to content

Commit e2ca90c

Browse files
Auto merge of #144699 - compiler-errors:extract-if-fulfill, r=<try>
Use `ExtractIf` in fulfillment loop
2 parents e5e79f8 + eb04ad7 commit e2ca90c

File tree

13 files changed

+84
-93
lines changed

13 files changed

+84
-93
lines changed

compiler/rustc_next_trait_solver/src/delegate.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use std::ops::Deref;
22

3+
use rustc_type_ir::inherent::*;
34
use rustc_type_ir::solve::{Certainty, Goal, NoSolution};
45
use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable};
56

7+
use crate::solve::GoalStalledOn;
8+
69
pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
710
type Infcx: InferCtxtLike<Interner = Self::Interner>;
811
type Interner: Interner;
@@ -23,6 +26,11 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
2326
span: <Self::Interner as Interner>::Span,
2427
) -> Option<Certainty>;
2528

29+
fn is_still_stalled(&self, stalled_on: &GoalStalledOn<Self::Interner>) -> bool {
30+
!stalled_on.stalled_vars.iter().any(|value| self.is_changed_arg(*value))
31+
&& !self.opaque_types_storage_num_entries().needs_reevaluation(stalled_on.num_opaques)
32+
}
33+
2634
fn fresh_var_for_kind_with_span(
2735
&self,
2836
arg: <Self::Interner as Interner>::GenericArg,

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,7 @@ where
431431
// args have changed. Otherwise, we don't need to re-run the goal because it'll remain
432432
// stalled, since it'll canonicalize the same way and evaluation is pure.
433433
if let Some(stalled_on) = stalled_on
434-
&& !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
435-
&& !self
436-
.delegate
437-
.opaque_types_storage_num_entries()
438-
.needs_reevaluation(stalled_on.num_opaques)
434+
&& self.delegate.is_still_stalled(&stalled_on)
439435
{
440436
return Ok((
441437
NestedNormalizationGoals::empty(),

compiler/rustc_trait_selection/src/solve/fulfill.rs

Lines changed: 41 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::marker::PhantomData;
2-
use std::mem;
32
use std::ops::ControlFlow;
43

54
use rustc_data_structures::thinvec::ExtractIf;
@@ -75,6 +74,13 @@ impl<'tcx> ObligationStorage<'tcx> {
7574
self.pending.push((obligation, stalled_on));
7675
}
7776

77+
fn register_overflowed(
78+
&mut self,
79+
overflowed: impl IntoIterator<Item = PredicateObligation<'tcx>>,
80+
) {
81+
self.overflowed.extend(overflowed);
82+
}
83+
7884
fn has_pending_obligations(&self) -> bool {
7985
!self.pending.is_empty() || !self.overflowed.is_empty()
8086
}
@@ -88,35 +94,10 @@ impl<'tcx> ObligationStorage<'tcx> {
8894

8995
fn drain_pending(
9096
&mut self,
91-
cond: impl Fn(&PredicateObligation<'tcx>) -> bool,
92-
) -> PendingObligations<'tcx> {
93-
let (unstalled, pending) =
94-
mem::take(&mut self.pending).into_iter().partition(|(o, _)| cond(o));
95-
self.pending = pending;
96-
unstalled
97-
}
98-
99-
fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) {
100-
infcx.probe(|_| {
101-
// IMPORTANT: we must not use solve any inference variables in the obligations
102-
// as this is all happening inside of a probe. We use a probe to make sure
103-
// we get all obligations involved in the overflow. We pretty much check: if
104-
// we were to do another step of `select_where_possible`, which goals would
105-
// change.
106-
// FIXME: <https://github.com/Gankra/thin-vec/pull/66> is merged, this can be removed.
107-
self.overflowed.extend(
108-
ExtractIf::new(&mut self.pending, |(o, stalled_on)| {
109-
let goal = o.as_goal();
110-
let result = <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
111-
goal,
112-
o.cause.span,
113-
stalled_on.take(),
114-
);
115-
matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. }))
116-
})
117-
.map(|(o, _)| o),
118-
);
119-
})
97+
cond: impl Fn(&PredicateObligation<'tcx>, Option<&GoalStalledOn<TyCtxt<'tcx>>>) -> bool,
98+
) -> impl Iterator<Item = (PredicateObligation<'tcx>, Option<GoalStalledOn<TyCtxt<'tcx>>>)>
99+
{
100+
ExtractIf::new(&mut self.pending, move |(o, stalled)| cond(o, stalled.as_ref()))
120101
}
121102
}
122103

@@ -133,21 +114,6 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> {
133114
_errors: PhantomData,
134115
}
135116
}
136-
137-
fn inspect_evaluated_obligation(
138-
&self,
139-
infcx: &InferCtxt<'tcx>,
140-
obligation: &PredicateObligation<'tcx>,
141-
result: &Result<GoalEvaluation<TyCtxt<'tcx>>, NoSolution>,
142-
) {
143-
if let Some(inspector) = infcx.obligation_inspector.get() {
144-
let result = match result {
145-
Ok(GoalEvaluation { certainty, .. }) => Ok(*certainty),
146-
Err(NoSolution) => Err(NoSolution),
147-
};
148-
(inspector)(infcx, &obligation, result);
149-
}
150-
}
151117
}
152118

153119
impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentCtxt<'tcx, E>
@@ -181,32 +147,42 @@ where
181147

182148
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
183149
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
150+
let delegate = <&SolverDelegate<'tcx>>::from(infcx);
184151
let mut errors = Vec::new();
185152
loop {
186153
let mut any_changed = false;
187-
for (mut obligation, stalled_on) in self.obligations.drain_pending(|_| true) {
154+
let mut overflowed = vec![];
155+
let mut pending = vec![];
156+
157+
for (mut obligation, stalled_on) in self.obligations.drain_pending(|_, stalled_on| {
158+
stalled_on.is_none_or(|s| !delegate.is_still_stalled(s))
159+
}) {
188160
if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
189-
self.obligations.on_fulfillment_overflow(infcx);
190-
// Only return true errors that we have accumulated while processing.
191-
return errors;
161+
overflowed.push(obligation);
162+
continue;
192163
}
193164

194165
let goal = obligation.as_goal();
195-
let delegate = <&SolverDelegate<'tcx>>::from(infcx);
196166
if let Some(certainty) =
197167
delegate.compute_goal_fast_path(goal, obligation.cause.span)
198168
{
199169
match certainty {
200170
Certainty::Yes => {}
201-
Certainty::Maybe(_) => {
202-
self.obligations.register(obligation, None);
203-
}
171+
Certainty::Maybe(_) => pending.push((obligation, None)),
204172
}
205173
continue;
206174
}
207175

208176
let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on);
209-
self.inspect_evaluated_obligation(infcx, &obligation, &result);
177+
178+
if let Some(inspector) = infcx.obligation_inspector.get() {
179+
let result = match result {
180+
Ok(GoalEvaluation { certainty, .. }) => Ok(certainty),
181+
Err(NoSolution) => Err(NoSolution),
182+
};
183+
(inspector)(infcx, &obligation, result);
184+
}
185+
210186
let GoalEvaluation { certainty, has_changed, stalled_on } = match result {
211187
Ok(result) => result,
212188
Err(NoSolution) => {
@@ -231,10 +207,19 @@ where
231207

232208
match certainty {
233209
Certainty::Yes => {}
234-
Certainty::Maybe(_) => self.obligations.register(obligation, stalled_on),
210+
Certainty::Maybe(_) => pending.push((obligation, stalled_on)),
235211
}
236212
}
237213

214+
if !overflowed.is_empty() {
215+
self.obligations.register_overflowed(overflowed);
216+
return errors;
217+
}
218+
219+
for (obligation, stalled_on) in pending {
220+
self.obligations.register(obligation, stalled_on);
221+
}
222+
238223
if !any_changed {
239224
break;
240225
}
@@ -270,7 +255,7 @@ where
270255
}
271256

272257
self.obligations
273-
.drain_pending(|obl| {
258+
.drain_pending(|obl, _| {
274259
infcx.probe(|_| {
275260
infcx
276261
.visit_proof_tree(

tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ LL | build(x)
55
| ^^^^^^^^ cannot normalize `build<_>::{opaque#0}`
66

77
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
8-
--> $DIR/recursive-in-exhaustiveness.rs:30:6
8+
--> $DIR/recursive-in-exhaustiveness.rs:30:5
99
|
1010
LL | (build2(x),)
11-
| ^^^^^^^^^ types differ
11+
| ^^^^^^^^^^^^ types differ
1212

1313
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
14-
--> $DIR/recursive-in-exhaustiveness.rs:30:5
14+
--> $DIR/recursive-in-exhaustiveness.rs:30:6
1515
|
1616
LL | (build2(x),)
17-
| ^^^^^^^^^^^^ types differ
17+
| ^^^^^^^^^ types differ
1818

1919
error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
2020
--> $DIR/recursive-in-exhaustiveness.rs:30:5

tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
22
--> $DIR/two_tait_defining_each_other2.rs:12:11
33
|
44
LL | fn muh(x: A) -> B {
5-
| ^ cannot infer type
5+
| ^ cannot infer type for type alias `A`
66

77
error: aborting due to 1 previous error
88

tests/ui/traits/next-solver/alias-bound-unsound.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ fn main() {
2525
//~^ ERROR overflow evaluating the requirement `String <: <() as Foo>::Item`
2626
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed`
2727
//~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed`
28+
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized`
2829
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
2930
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
3031
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`

tests/ui/traits/next-solver/alias-bound-unsound.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ LL | drop(<() as Foo>::copy_me(&x));
3232
|
3333
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
3434

35+
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Sized`
36+
--> $DIR/alias-bound-unsound.rs:24:10
37+
|
38+
LL | drop(<() as Foo>::copy_me(&x));
39+
| ^^^^^^^^^^^^^^^^^^^^^^^^
40+
|
41+
= note: the return type of a function must have a statically known size
42+
3543
error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed`
3644
--> $DIR/alias-bound-unsound.rs:24:31
3745
|
@@ -58,6 +66,6 @@ error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
5866
LL | drop(<() as Foo>::copy_me(&x));
5967
| ^^
6068

61-
error: aborting due to 8 previous errors
69+
error: aborting due to 9 previous errors
6270

6371
For more information about this error, try `rustc --explain E0275`.
Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
error[E0283]: type annotations needed
1+
error[E0284]: type annotations needed: cannot normalize `<_ as Iterator>::Item`
22
--> $DIR/runaway-impl-candidate-selection.rs:13:22
33
|
44
LL | println!("{:?}", iter::<_>());
5-
| ^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `iter`
6-
|
7-
= note: cannot satisfy `_: Iterator`
8-
note: required by a bound in `iter`
9-
--> $DIR/runaway-impl-candidate-selection.rs:8:12
10-
|
11-
LL | fn iter<T: Iterator>() -> <T as Iterator>::Item {
12-
| ^^^^^^^^ required by this bound in `iter`
5+
| ^^^^^^^^^^^ cannot normalize `<_ as Iterator>::Item`
136

147
error: aborting due to 1 previous error
158

16-
For more information about this error, try `rustc --explain E0283`.
9+
For more information about this error, try `rustc --explain E0284`.

tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ LL | impl<T: TwoW> Trait for W<T> {}
55
| ---------------------------- first implementation here
66
LL | impl<T: TwoW> Trait for T {}
77
| ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`
8+
|
9+
= note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>: TwoW`
10+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`)
811

912
error: aborting due to 1 previous error
1013

tests/ui/traits/next-solver/coroutine.fail.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ LL | | },
1111
| |_________^ the trait `Coroutine<A>` is not implemented for `{coroutine@$DIR/coroutine.rs:20:9: 20:11}`
1212
|
1313
note: required by a bound in `needs_coroutine`
14-
--> $DIR/coroutine.rs:14:28
14+
--> $DIR/coroutine.rs:14:41
1515
|
1616
LL | fn needs_coroutine(_: impl Coroutine<A, Yield = B, Return = C>) {}
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_coroutine`
17+
| ^^^^^^^^^ required by this bound in `needs_coroutine`
1818

1919
error: aborting due to 1 previous error
2020

0 commit comments

Comments
 (0)