Skip to content

Commit a1f8edb

Browse files
Rollup merge of #113317 - lcnr:sketchy-new-select, r=oli-obk
-Ztrait-solver=next: stop depending on old solver removes the final dependencies on the old solver when `-Ztrait-solver=next` is enabled.
2 parents 1cb958a + 3129942 commit a1f8edb

File tree

9 files changed

+87
-84
lines changed

9 files changed

+87
-84
lines changed

Diff for: compiler/rustc_infer/src/infer/projection.rs

+13-24
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,18 @@ impl<'tcx> InferCtxt<'tcx> {
2121
recursion_depth: usize,
2222
obligations: &mut Vec<PredicateObligation<'tcx>>,
2323
) -> Ty<'tcx> {
24-
if self.next_trait_solver() {
25-
// FIXME(-Ztrait-solver=next): Instead of branching here,
26-
// completely change the normalization routine with the new solver.
27-
//
28-
// The new solver correctly handles projection equality so this hack
29-
// is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
30-
// not `PredicateKind::Clause(ClauseKind::Projection(..))` as in the new solver
31-
// `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
32-
return projection_ty.to_ty(self.tcx);
33-
} else {
34-
let def_id = projection_ty.def_id;
35-
let ty_var = self.next_ty_var(TypeVariableOrigin {
36-
kind: TypeVariableOriginKind::NormalizeProjectionType,
37-
span: self.tcx.def_span(def_id),
38-
});
39-
let projection =
40-
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
41-
ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
42-
)));
43-
let obligation =
44-
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
45-
obligations.push(obligation);
46-
ty_var
47-
}
24+
debug_assert!(!self.next_trait_solver());
25+
let def_id = projection_ty.def_id;
26+
let ty_var = self.next_ty_var(TypeVariableOrigin {
27+
kind: TypeVariableOriginKind::NormalizeProjectionType,
28+
span: self.tcx.def_span(def_id),
29+
});
30+
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
31+
ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
32+
)));
33+
let obligation =
34+
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
35+
obligations.push(obligation);
36+
ty_var
4837
}
4938
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
159159
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
160160
let reveal = self.at.param_env.reveal();
161161
let infcx = self.at.infcx;
162+
debug_assert_eq!(ty, infcx.shallow_resolve(ty));
162163
if !needs_normalization(&ty, reveal) {
163164
return Ok(ty);
164165
}
@@ -192,6 +193,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
192193
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
193194
let reveal = self.at.param_env.reveal();
194195
let infcx = self.at.infcx;
196+
debug_assert_eq!(ct, infcx.shallow_resolve(ct));
195197
if !needs_normalization(&ct, reveal) {
196198
return Ok(ct);
197199
}

Diff for: compiler/rustc_trait_selection/src/traits/coherence.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use std::fmt::Debug;
3030
use std::iter;
3131
use std::ops::ControlFlow;
3232

33+
use super::query::evaluate_obligation::InferCtxtExt;
3334
use super::NormalizeExt;
3435

3536
/// Whether we do the orphan check relative to this crate or
@@ -290,19 +291,28 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
290291
) -> bool {
291292
let infcx = selcx.infcx;
292293

294+
let obligation_guaranteed_to_fail = move |obligation: &PredicateObligation<'tcx>| {
295+
if infcx.next_trait_solver() {
296+
infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply())
297+
} else {
298+
// We use `evaluate_root_obligation` to correctly track
299+
// intercrate ambiguity clauses. We do not need this in the
300+
// new solver.
301+
selcx.evaluate_root_obligation(obligation).map_or(
302+
false, // Overflow has occurred, and treat the obligation as possibly holding.
303+
|result| !result.may_apply(),
304+
)
305+
}
306+
};
307+
293308
let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates]
294309
.into_iter()
295310
.flatten()
296311
.map(|&predicate| {
297312
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
298313
})
299314
.chain(obligations)
300-
.find(|o| {
301-
selcx.evaluate_root_obligation(o).map_or(
302-
false, // Overflow has occurred, and treat the obligation as possibly holding.
303-
|result| !result.may_apply(),
304-
)
305-
});
315+
.find(obligation_guaranteed_to_fail);
306316

307317
if let Some(failing_obligation) = opt_failing_obligation {
308318
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);

Diff for: compiler/rustc_trait_selection/src/traits/project.rs

+2
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
447447
depth: usize,
448448
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
449449
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
450+
debug_assert!(!selcx.infcx.next_trait_solver());
450451
AssocTypeNormalizer {
451452
selcx,
452453
param_env,
@@ -1122,6 +1123,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
11221123
obligations: &mut Vec<PredicateObligation<'tcx>>,
11231124
) -> Result<Option<Term<'tcx>>, InProgress> {
11241125
let infcx = selcx.infcx;
1126+
debug_assert!(!selcx.infcx.next_trait_solver());
11251127
// Don't use the projection cache in intercrate mode -
11261128
// the `infcx` may be re-used between intercrate in non-intercrate
11271129
// mode, which could lead to using incorrect cache results.

Diff for: compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
9797
}
9898
})
9999
} else {
100+
assert!(!self.intercrate);
100101
let c_pred = self.canonicalize_query_keep_static(
101102
param_env.and(obligation.predicate),
102103
&mut _orig_values,

Diff for: compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs

+20-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::solve;
12
use crate::traits::query::NoSolution;
23
use crate::traits::wf;
34
use crate::traits::ObligationCtxt;
@@ -6,6 +7,7 @@ use rustc_infer::infer::canonical::Canonical;
67
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
78
use rustc_infer::traits::query::OutlivesBound;
89
use rustc_middle::infer::canonical::CanonicalQueryResponse;
10+
use rustc_middle::traits::ObligationCause;
911
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
1012
use rustc_span::def_id::CRATE_DEF_ID;
1113
use rustc_span::source_map::DUMMY_SP;
@@ -164,19 +166,29 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
164166

165167
// We lazily compute the outlives components as
166168
// `select_all_or_error` constrains inference variables.
167-
let implied_bounds = outlives_bounds
168-
.into_iter()
169-
.flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
170-
ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
169+
let mut implied_bounds = Vec::new();
170+
for ty::OutlivesPredicate(a, r_b) in outlives_bounds {
171+
match a.unpack() {
172+
ty::GenericArgKind::Lifetime(r_a) => {
173+
implied_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a))
174+
}
171175
ty::GenericArgKind::Type(ty_a) => {
172-
let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
176+
let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
177+
// Need to manually normalize in the new solver as `wf::obligations` does not.
178+
if ocx.infcx.next_trait_solver() {
179+
ty_a = solve::deeply_normalize(
180+
ocx.infcx.at(&ObligationCause::dummy(), param_env),
181+
ty_a,
182+
)
183+
.map_err(|_errs| NoSolution)?;
184+
}
173185
let mut components = smallvec![];
174186
push_outlives_components(tcx, ty_a, &mut components);
175-
implied_bounds_from_components(r_b, components)
187+
implied_bounds.extend(implied_bounds_from_components(r_b, components))
176188
}
177189
ty::GenericArgKind::Const(_) => unreachable!(),
178-
})
179-
.collect();
190+
}
191+
}
180192

181193
Ok(implied_bounds)
182194
}

Diff for: compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
388388
/// `FnPtr`, when we wanted to report that it doesn't implement `Trait`.
389389
#[instrument(level = "trace", skip(self), ret)]
390390
fn reject_fn_ptr_impls(
391-
&self,
391+
&mut self,
392392
impl_def_id: DefId,
393393
obligation: &TraitObligation<'tcx>,
394394
impl_self_ty: Ty<'tcx>,
@@ -464,7 +464,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
464464
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
465465
})),
466466
);
467-
if let Ok(r) = self.infcx.evaluate_obligation(&obligation) {
467+
if let Ok(r) = self.evaluate_root_obligation(&obligation) {
468468
if !r.may_apply() {
469469
return true;
470470
}

Diff for: compiler/rustc_trait_selection/src/traits/select/mod.rs

+21-44
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ use rustc_hir as hir;
3434
use rustc_hir::def_id::DefId;
3535
use rustc_infer::infer::DefineOpaqueTypes;
3636
use rustc_infer::infer::LateBoundRegionConversionTime;
37-
use rustc_infer::traits::TraitEngine;
38-
use rustc_infer::traits::TraitEngineExt;
3937
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
4038
use rustc_middle::mir::interpret::ErrorHandled;
4139
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -312,6 +310,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
312310
&mut self,
313311
stack: &TraitObligationStack<'o, 'tcx>,
314312
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
313+
debug_assert!(!self.infcx.next_trait_solver());
315314
// Watch out for overflow. This intentionally bypasses (and does
316315
// not update) the cache.
317316
self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
@@ -526,21 +525,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
526525
/// Evaluates whether the obligation `obligation` can be satisfied
527526
/// and returns an `EvaluationResult`. This is meant for the
528527
/// *initial* call.
528+
///
529+
/// Do not use this directly, use `infcx.evaluate_obligation` instead.
529530
pub fn evaluate_root_obligation(
530531
&mut self,
531532
obligation: &PredicateObligation<'tcx>,
532533
) -> Result<EvaluationResult, OverflowError> {
534+
debug_assert!(!self.infcx.next_trait_solver());
533535
self.evaluation_probe(|this| {
534536
let goal =
535537
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
536-
let mut result = if this.infcx.next_trait_solver() {
537-
this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])?
538-
} else {
539-
this.evaluate_predicate_recursively(
540-
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
541-
obligation.clone(),
542-
)?
543-
};
538+
let mut result = this.evaluate_predicate_recursively(
539+
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
540+
obligation.clone(),
541+
)?;
544542
// If the predicate has done any inference, then downgrade the
545543
// result to ambiguous.
546544
if this.infcx.shallow_resolve(goal) != goal {
@@ -587,42 +585,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
587585
where
588586
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
589587
{
590-
if self.infcx.next_trait_solver() {
591-
self.evaluate_predicates_recursively_in_new_solver(predicates)
592-
} else {
593-
let mut result = EvaluatedToOk;
594-
for mut obligation in predicates {
595-
obligation.set_depth_from_parent(stack.depth());
596-
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
597-
if let EvaluatedToErr = eval {
598-
// fast-path - EvaluatedToErr is the top of the lattice,
599-
// so we don't need to look on the other predicates.
600-
return Ok(EvaluatedToErr);
601-
} else {
602-
result = cmp::max(result, eval);
603-
}
588+
let mut result = EvaluatedToOk;
589+
for mut obligation in predicates {
590+
obligation.set_depth_from_parent(stack.depth());
591+
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
592+
if let EvaluatedToErr = eval {
593+
// fast-path - EvaluatedToErr is the top of the lattice,
594+
// so we don't need to look on the other predicates.
595+
return Ok(EvaluatedToErr);
596+
} else {
597+
result = cmp::max(result, eval);
604598
}
605-
Ok(result)
606-
}
607-
}
608-
609-
/// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled
610-
fn evaluate_predicates_recursively_in_new_solver(
611-
&mut self,
612-
predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>,
613-
) -> Result<EvaluationResult, OverflowError> {
614-
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self.infcx);
615-
fulfill_cx.register_predicate_obligations(self.infcx, predicates);
616-
// True errors
617-
// FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
618-
if !fulfill_cx.select_where_possible(self.infcx).is_empty() {
619-
return Ok(EvaluatedToErr);
620599
}
621-
if !fulfill_cx.select_all_or_error(self.infcx).is_empty() {
622-
return Ok(EvaluatedToAmbig);
623-
}
624-
// Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot
625-
Ok(EvaluatedToOk)
600+
Ok(result)
626601
}
627602

628603
#[instrument(
@@ -636,6 +611,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
636611
previous_stack: TraitObligationStackList<'o, 'tcx>,
637612
obligation: PredicateObligation<'tcx>,
638613
) -> Result<EvaluationResult, OverflowError> {
614+
debug_assert!(!self.infcx.next_trait_solver());
639615
// `previous_stack` stores a `TraitObligation`, while `obligation` is
640616
// a `PredicateObligation`. These are distinct types, so we can't
641617
// use any `Option` combinator method that would force them to be
@@ -1179,6 +1155,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11791155
&mut self,
11801156
stack: &TraitObligationStack<'o, 'tcx>,
11811157
) -> Result<EvaluationResult, OverflowError> {
1158+
debug_assert!(!self.infcx.next_trait_solver());
11821159
// In intercrate mode, whenever any of the generics are unbound,
11831160
// there can always be an impl. Even if there are no impls in
11841161
// this crate, perhaps the type would be unified with

Diff for: compiler/rustc_trait_selection/src/traits/wf.rs

+10
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,16 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
302302
}
303303

304304
fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
305+
// Do not normalize `wf` obligations with the new solver.
306+
//
307+
// The current deep normalization routine with the new solver does not
308+
// handle ambiguity and the new solver correctly deals with unnnormalized goals.
309+
// If the user relies on normalized types, e.g. for `fn implied_outlives_bounds`,
310+
// it is their responsibility to normalize while avoiding ambiguity.
311+
if infcx.next_trait_solver() {
312+
return self.out;
313+
}
314+
305315
let cause = self.cause(traits::WellFormed(None));
306316
let param_env = self.param_env;
307317
let mut obligations = Vec::with_capacity(self.out.len());

0 commit comments

Comments
 (0)