Skip to content

Commit fca59ab

Browse files
committed
Auto merge of rust-lang#114492 - compiler-errors:rollup-lp4sfla, r=compiler-errors
Rollup of 5 pull requests Successful merges: - rust-lang#114287 (update overflow handling in the new trait solver) - rust-lang#114475 (Migrate GUI colors test to original CSS color format) - rust-lang#114482 (Fix ui-fulldeps missing the `internal_features` lint on stage 0) - rust-lang#114490 (Fix a typo in the error reporting for sealed traits.) - rust-lang#114491 (Rename issue rust-lang#114423 test files to include context) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 90f0b24 + 3222084 commit fca59ab

32 files changed

+770
-586
lines changed

Diff for: compiler/rustc_middle/src/traits/solve.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::ops::ControlFlow;
22

33
use rustc_data_structures::intern::Interned;
4-
use rustc_query_system::cache::Cache;
54

65
use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
76
use crate::traits::query::NoSolution;
@@ -11,9 +10,10 @@ use crate::ty::{
1110
TypeVisitor,
1211
};
1312

13+
mod cache;
1414
pub mod inspect;
1515

16-
pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>;
16+
pub use cache::{CacheData, EvaluationCache};
1717

1818
/// A goal is a statement, i.e. `predicate`, we want to prove
1919
/// given some assumptions, i.e. `param_env`.

Diff for: compiler/rustc_middle/src/traits/solve/cache.rs

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use super::{CanonicalInput, QueryResult};
2+
use crate::ty::TyCtxt;
3+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4+
use rustc_data_structures::sync::Lock;
5+
use rustc_query_system::cache::WithDepNode;
6+
use rustc_query_system::dep_graph::DepNodeIndex;
7+
use rustc_session::Limit;
8+
/// The trait solver cache used by `-Ztrait-solver=next`.
9+
///
10+
/// FIXME(@lcnr): link to some official documentation of how
11+
/// this works.
12+
#[derive(Default)]
13+
pub struct EvaluationCache<'tcx> {
14+
map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>,
15+
}
16+
17+
pub struct CacheData<'tcx> {
18+
pub result: QueryResult<'tcx>,
19+
pub reached_depth: usize,
20+
pub encountered_overflow: bool,
21+
}
22+
23+
impl<'tcx> EvaluationCache<'tcx> {
24+
/// Insert a final result into the global cache.
25+
pub fn insert(
26+
&self,
27+
key: CanonicalInput<'tcx>,
28+
reached_depth: usize,
29+
did_overflow: bool,
30+
cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
31+
dep_node: DepNodeIndex,
32+
result: QueryResult<'tcx>,
33+
) {
34+
let mut map = self.map.borrow_mut();
35+
let entry = map.entry(key).or_default();
36+
let data = WithDepNode::new(dep_node, result);
37+
entry.cycle_participants.extend(cycle_participants);
38+
if did_overflow {
39+
entry.with_overflow.insert(reached_depth, data);
40+
} else {
41+
entry.success = Some(Success { data, reached_depth });
42+
}
43+
}
44+
45+
/// Try to fetch a cached result, checking the recursion limit
46+
/// and handling root goals of coinductive cycles.
47+
///
48+
/// If this returns `Some` the cache result can be used.
49+
pub fn get(
50+
&self,
51+
tcx: TyCtxt<'tcx>,
52+
key: CanonicalInput<'tcx>,
53+
cycle_participant_in_stack: impl FnOnce(&FxHashSet<CanonicalInput<'tcx>>) -> bool,
54+
available_depth: Limit,
55+
) -> Option<CacheData<'tcx>> {
56+
let map = self.map.borrow();
57+
let entry = map.get(&key)?;
58+
59+
if cycle_participant_in_stack(&entry.cycle_participants) {
60+
return None;
61+
}
62+
63+
if let Some(ref success) = entry.success {
64+
if available_depth.value_within_limit(success.reached_depth) {
65+
return Some(CacheData {
66+
result: success.data.get(tcx),
67+
reached_depth: success.reached_depth,
68+
encountered_overflow: false,
69+
});
70+
}
71+
}
72+
73+
entry.with_overflow.get(&available_depth.0).map(|e| CacheData {
74+
result: e.get(tcx),
75+
reached_depth: available_depth.0,
76+
encountered_overflow: true,
77+
})
78+
}
79+
}
80+
81+
struct Success<'tcx> {
82+
data: WithDepNode<QueryResult<'tcx>>,
83+
reached_depth: usize,
84+
}
85+
86+
/// The cache entry for a goal `CanonicalInput`.
87+
///
88+
/// This contains results whose computation never hit the
89+
/// recursion limit in `success`, and all results which hit
90+
/// the recursion limit in `with_overflow`.
91+
#[derive(Default)]
92+
struct CacheEntry<'tcx> {
93+
success: Option<Success<'tcx>>,
94+
/// We have to be careful when caching roots of cycles.
95+
///
96+
/// See the doc comment of `StackEntry::cycle_participants` for more
97+
/// details.
98+
cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
99+
with_overflow: FxHashMap<usize, WithDepNode<QueryResult<'tcx>>>,
100+
}

Diff for: compiler/rustc_middle/src/ty/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1338,12 +1338,25 @@ impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
13381338
}
13391339
}
13401340

1341+
impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> {
1342+
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
1343+
ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx)
1344+
}
1345+
}
1346+
13411347
impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
13421348
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
13431349
self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx)
13441350
}
13451351
}
13461352

1353+
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> {
1354+
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
1355+
let p: Predicate<'tcx> = self.to_predicate(tcx);
1356+
p.expect_clause()
1357+
}
1358+
}
1359+
13471360
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
13481361
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
13491362
let p: Predicate<'tcx> = self.to_predicate(tcx);

Diff for: compiler/rustc_trait_selection/src/solve/alias_relate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
162162
self.add_goal(Goal::new(
163163
self.tcx(),
164164
param_env,
165-
ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }),
165+
ty::ProjectionPredicate { projection_ty: alias, term: other },
166166
));
167167

168168
Ok(())

Diff for: compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+34-43
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Code shared by trait and projection goals for candidate assembly.
22
3-
use super::search_graph::OverflowHandler;
43
use super::{EvalCtxt, SolverMode};
54
use crate::traits::coherence;
65
use rustc_hir::def_id::DefId;
@@ -315,7 +314,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
315314
return ambig;
316315
}
317316

318-
let mut candidates = self.assemble_candidates_via_self_ty(goal);
317+
let mut candidates = self.assemble_candidates_via_self_ty(goal, 0);
319318

320319
self.assemble_blanket_impl_candidates(goal, &mut candidates);
321320

@@ -351,6 +350,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
351350
fn assemble_candidates_via_self_ty<G: GoalKind<'tcx>>(
352351
&mut self,
353352
goal: Goal<'tcx, G>,
353+
num_steps: usize,
354354
) -> Vec<Candidate<'tcx>> {
355355
debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
356356
if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
@@ -369,7 +369,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
369369

370370
self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
371371

372-
self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates);
372+
self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates, num_steps);
373373

374374
candidates
375375
}
@@ -393,49 +393,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
393393
&mut self,
394394
goal: Goal<'tcx, G>,
395395
candidates: &mut Vec<Candidate<'tcx>>,
396+
num_steps: usize,
396397
) {
397398
let tcx = self.tcx();
398399
let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else { return };
399400

400-
let normalized_self_candidates: Result<_, NoSolution> =
401-
self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| {
402-
ecx.with_incremented_depth(
403-
|ecx| {
404-
let result = ecx.evaluate_added_goals_and_make_canonical_response(
405-
Certainty::OVERFLOW,
406-
)?;
407-
Ok(vec![Candidate {
408-
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
409-
result,
410-
}])
411-
},
412-
|ecx| {
413-
let normalized_ty = ecx.next_ty_infer();
414-
let normalizes_to_goal = goal.with(
415-
tcx,
416-
ty::Binder::dummy(ty::ProjectionPredicate {
417-
projection_ty,
418-
term: normalized_ty.into(),
419-
}),
420-
);
421-
ecx.add_goal(normalizes_to_goal);
422-
let _ = ecx.try_evaluate_added_goals().inspect_err(|_| {
423-
debug!("self type normalization failed");
424-
})?;
425-
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
426-
debug!(?normalized_ty, "self type normalized");
427-
// NOTE: Alternatively we could call `evaluate_goal` here and only
428-
// have a `Normalized` candidate. This doesn't work as long as we
429-
// use `CandidateSource` in winnowing.
430-
let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
431-
Ok(ecx.assemble_candidates_via_self_ty(goal))
432-
},
433-
)
434-
});
435-
436-
if let Ok(normalized_self_candidates) = normalized_self_candidates {
437-
candidates.extend(normalized_self_candidates);
438-
}
401+
candidates.extend(self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| {
402+
if num_steps < ecx.local_overflow_limit() {
403+
let normalized_ty = ecx.next_ty_infer();
404+
let normalizes_to_goal = goal.with(
405+
tcx,
406+
ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() },
407+
);
408+
ecx.add_goal(normalizes_to_goal);
409+
if let Err(NoSolution) = ecx.try_evaluate_added_goals() {
410+
debug!("self type normalization failed");
411+
return vec![];
412+
}
413+
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
414+
debug!(?normalized_ty, "self type normalized");
415+
// NOTE: Alternatively we could call `evaluate_goal` here and only
416+
// have a `Normalized` candidate. This doesn't work as long as we
417+
// use `CandidateSource` in winnowing.
418+
let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
419+
ecx.assemble_candidates_via_self_ty(goal, num_steps + 1)
420+
} else {
421+
match ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) {
422+
Ok(result) => vec![Candidate {
423+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
424+
result,
425+
}],
426+
Err(NoSolution) => vec![],
427+
}
428+
}
429+
}));
439430
}
440431

441432
#[instrument(level = "debug", skip_all)]
@@ -533,7 +524,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
533524
ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
534525

535526
// FIXME: These should ideally not exist as a self type. It would be nice for
536-
// the builtin auto trait impls of generators should instead directly recurse
527+
// the builtin auto trait impls of generators to instead directly recurse
537528
// into the witness.
538529
ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(_, _) => (),
539530

0 commit comments

Comments
 (0)