Skip to content

Commit 39ba110

Browse files
authored
Rollup merge of #107786 - compiler-errors:new-solver-some-tweaks, r=lcnr
Implement some tweaks in the new solver I've been testing the new solver on some small codebases, and these are a few small changes I've needed to make. The most "controversial" here is implementing `trait_candidate_should_be_dropped_in_favor_of`, which I just implemented to always return false. This surprisingly allows some code to compile, without us having to actually decide on any semantics yet. r? `@rust-lang/initiative-trait-system-refactor`
2 parents 5aa062e + 654f43f commit 39ba110

File tree

8 files changed

+129
-144
lines changed

8 files changed

+129
-144
lines changed

compiler/rustc_trait_selection/src/solve/assembly.rs

+76-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::infcx_ext::InferCtxtExt;
44
#[cfg(doc)]
55
use super::trait_goals::structural_traits::*;
6-
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
6+
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
77
use rustc_hir::def_id::DefId;
88
use rustc_infer::traits::query::NoSolution;
99
use rustc_infer::traits::util::elaborate_predicates;
@@ -399,10 +399,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
399399
ty::Alias(_, alias_ty) => alias_ty,
400400
};
401401

402-
for (assumption, _) in self
403-
.tcx()
404-
.bound_explicit_item_bounds(alias_ty.def_id)
405-
.subst_iter_copied(self.tcx(), alias_ty.substs)
402+
for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
406403
{
407404
match G::consider_assumption(self, goal, assumption) {
408405
Ok(result) => {
@@ -462,4 +459,78 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
462459
}
463460
}
464461
}
462+
463+
#[instrument(level = "debug", skip(self), ret)]
464+
pub(super) fn merge_candidates_and_discard_reservation_impls(
465+
&mut self,
466+
mut candidates: Vec<Candidate<'tcx>>,
467+
) -> QueryResult<'tcx> {
468+
match candidates.len() {
469+
0 => return Err(NoSolution),
470+
1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
471+
_ => {}
472+
}
473+
474+
if candidates.len() > 1 {
475+
let mut i = 0;
476+
'outer: while i < candidates.len() {
477+
for j in (0..candidates.len()).filter(|&j| i != j) {
478+
if self.trait_candidate_should_be_dropped_in_favor_of(
479+
&candidates[i],
480+
&candidates[j],
481+
) {
482+
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
483+
candidates.swap_remove(i);
484+
continue 'outer;
485+
}
486+
}
487+
488+
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
489+
i += 1;
490+
}
491+
492+
// If there are *STILL* multiple candidates, give up
493+
// and report ambiguity.
494+
if candidates.len() > 1 {
495+
let certainty = if candidates.iter().all(|x| {
496+
matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow))
497+
}) {
498+
Certainty::Maybe(MaybeCause::Overflow)
499+
} else {
500+
Certainty::AMBIGUOUS
501+
};
502+
return self.make_canonical_response(certainty);
503+
}
504+
}
505+
506+
Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
507+
}
508+
509+
fn trait_candidate_should_be_dropped_in_favor_of(
510+
&self,
511+
candidate: &Candidate<'tcx>,
512+
other: &Candidate<'tcx>,
513+
) -> bool {
514+
// FIXME: implement this
515+
match (candidate.source, other.source) {
516+
(CandidateSource::Impl(_), _)
517+
| (CandidateSource::ParamEnv(_), _)
518+
| (CandidateSource::AliasBound, _)
519+
| (CandidateSource::BuiltinImpl, _) => false,
520+
}
521+
}
522+
523+
fn discard_reservation_impl(&self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
524+
if let CandidateSource::Impl(def_id) = candidate.source {
525+
if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
526+
debug!("Selected reservation impl");
527+
// We assemble all candidates inside of a probe so by
528+
// making a new canonical response here our result will
529+
// have no constraints.
530+
candidate.result = self.make_canonical_response(Certainty::AMBIGUOUS).unwrap();
531+
}
532+
}
533+
534+
candidate
535+
}
465536
}

compiler/rustc_trait_selection/src/solve/project_goals.rs

+4-56
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::traits::{specialization_graph, translate_substs};
22

3-
use super::assembly::{self, Candidate, CandidateSource};
3+
use super::assembly;
44
use super::infcx_ext::InferCtxtExt;
55
use super::trait_goals::structural_traits;
66
use super::{Certainty, EvalCtxt, Goal, QueryResult};
@@ -34,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
3434
// projection cache in the solver.
3535
if self.term_is_fully_unconstrained(goal) {
3636
let candidates = self.assemble_and_evaluate_candidates(goal);
37-
self.merge_project_candidates(candidates)
37+
self.merge_candidates_and_discard_reservation_impls(candidates)
3838
} else {
3939
let predicate = goal.predicate;
4040
let unconstrained_rhs = match predicate.term.unpack() {
@@ -153,59 +153,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
153153

154154
self.make_canonical_response(normalization_certainty.unify_and(rhs_certainty))
155155
}
156-
157-
fn merge_project_candidates(
158-
&mut self,
159-
mut candidates: Vec<Candidate<'tcx>>,
160-
) -> QueryResult<'tcx> {
161-
match candidates.len() {
162-
0 => return Err(NoSolution),
163-
1 => return Ok(candidates.pop().unwrap().result),
164-
_ => {}
165-
}
166-
167-
if candidates.len() > 1 {
168-
let mut i = 0;
169-
'outer: while i < candidates.len() {
170-
for j in (0..candidates.len()).filter(|&j| i != j) {
171-
if self.project_candidate_should_be_dropped_in_favor_of(
172-
&candidates[i],
173-
&candidates[j],
174-
) {
175-
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
176-
candidates.swap_remove(i);
177-
continue 'outer;
178-
}
179-
}
180-
181-
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
182-
// If there are *STILL* multiple candidates, give up
183-
// and report ambiguity.
184-
i += 1;
185-
if i > 1 {
186-
debug!("multiple matches, ambig");
187-
// FIXME: return overflow if all candidates overflow, otherwise return ambiguity.
188-
unimplemented!();
189-
}
190-
}
191-
}
192-
193-
Ok(candidates.pop().unwrap().result)
194-
}
195-
196-
fn project_candidate_should_be_dropped_in_favor_of(
197-
&self,
198-
candidate: &Candidate<'tcx>,
199-
other: &Candidate<'tcx>,
200-
) -> bool {
201-
// FIXME: implement this
202-
match (candidate.source, other.source) {
203-
(CandidateSource::Impl(_), _)
204-
| (CandidateSource::ParamEnv(_), _)
205-
| (CandidateSource::BuiltinImpl, _)
206-
| (CandidateSource::AliasBound, _) => unimplemented!(),
207-
}
208-
}
209156
}
210157

211158
impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
@@ -452,7 +399,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
452399
[ty::GenericArg::from(goal.predicate.self_ty())],
453400
));
454401

455-
let is_sized_certainty = ecx.evaluate_goal(goal.with(tcx, sized_predicate))?.1;
402+
let (_, is_sized_certainty) =
403+
ecx.evaluate_goal(goal.with(tcx, sized_predicate))?;
456404
return ecx.eq_term_and_make_canonical_response(
457405
goal,
458406
is_sized_certainty,

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+2-69
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::iter;
44

5-
use super::assembly::{self, Candidate, CandidateSource};
5+
use super::assembly;
66
use super::infcx_ext::InferCtxtExt;
77
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
88
use rustc_hir::def_id::DefId;
@@ -479,73 +479,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
479479
goal: Goal<'tcx, TraitPredicate<'tcx>>,
480480
) -> QueryResult<'tcx> {
481481
let candidates = self.assemble_and_evaluate_candidates(goal);
482-
self.merge_trait_candidates_discard_reservation_impls(candidates)
483-
}
484-
485-
#[instrument(level = "debug", skip(self), ret)]
486-
pub(super) fn merge_trait_candidates_discard_reservation_impls(
487-
&mut self,
488-
mut candidates: Vec<Candidate<'tcx>>,
489-
) -> QueryResult<'tcx> {
490-
match candidates.len() {
491-
0 => return Err(NoSolution),
492-
1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
493-
_ => {}
494-
}
495-
496-
if candidates.len() > 1 {
497-
let mut i = 0;
498-
'outer: while i < candidates.len() {
499-
for j in (0..candidates.len()).filter(|&j| i != j) {
500-
if self.trait_candidate_should_be_dropped_in_favor_of(
501-
&candidates[i],
502-
&candidates[j],
503-
) {
504-
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
505-
candidates.swap_remove(i);
506-
continue 'outer;
507-
}
508-
}
509-
510-
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
511-
// If there are *STILL* multiple candidates, give up
512-
// and report ambiguity.
513-
i += 1;
514-
if i > 1 {
515-
debug!("multiple matches, ambig");
516-
// FIXME: return overflow if all candidates overflow, otherwise return ambiguity.
517-
unimplemented!();
518-
}
519-
}
520-
}
521-
522-
Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
523-
}
524-
525-
fn trait_candidate_should_be_dropped_in_favor_of(
526-
&self,
527-
candidate: &Candidate<'tcx>,
528-
other: &Candidate<'tcx>,
529-
) -> bool {
530-
// FIXME: implement this
531-
match (candidate.source, other.source) {
532-
(CandidateSource::Impl(_), _)
533-
| (CandidateSource::ParamEnv(_), _)
534-
| (CandidateSource::AliasBound, _)
535-
| (CandidateSource::BuiltinImpl, _) => unimplemented!(),
536-
}
537-
}
538-
539-
fn discard_reservation_impl(&self, candidate: Candidate<'tcx>) -> Candidate<'tcx> {
540-
if let CandidateSource::Impl(def_id) = candidate.source {
541-
if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
542-
debug!("Selected reservation impl");
543-
// FIXME: reduce candidate to ambiguous
544-
// FIXME: replace `var_values` with identity, yeet external constraints.
545-
unimplemented!()
546-
}
547-
}
548-
549-
candidate
482+
self.merge_candidates_and_discard_reservation_impls(candidates)
550483
}
551484
}

compiler/rustc_trait_selection/src/traits/object_safety.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -646,11 +646,9 @@ fn object_ty_for_trait<'tcx>(
646646
debug!(?obligation);
647647
let pred = obligation.predicate.to_opt_poly_projection_pred()?;
648648
Some(pred.map_bound(|p| {
649-
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
650-
def_id: p.projection_ty.def_id,
651-
substs: p.projection_ty.substs,
652-
term: p.term,
653-
})
649+
ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
650+
tcx, p,
651+
))
654652
}))
655653
})
656654
.collect();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// check-pass
3+
4+
trait Foo {
5+
type Bar: Bar;
6+
}
7+
8+
trait Bar: Baz {}
9+
10+
trait Baz {}
11+
12+
fn main() {}

tests/ui/traits/new-solver/provisional-result-done.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
// known-bug: unknown
22
// compile-flags: -Ztrait-solver=next
3-
// failure-status: 101
4-
// normalize-stderr-test "note: .*\n\n" -> ""
5-
// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
6-
// rustc-env:RUST_BACKTRACE=0
73

84
// This tests checks that we update results in the provisional cache when
95
// we pop a goal from the stack.
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
error: the compiler unexpectedly panicked. this is a bug.
1+
error[E0283]: type annotations needed: cannot satisfy `Bar<T>: Coinductive`
2+
--> $DIR/provisional-result-done.rs:16:25
3+
|
4+
LL | impl<T> Coinductive for Bar<T>
5+
| ^^^^^^
6+
|
7+
= note: cannot satisfy `Bar<T>: Coinductive`
28

3-
query stack during panic:
4-
#0 [check_well_formed] checking that `<impl at $DIR/provisional-result-done.rs:20:1: 20:31>` is well-formed
5-
#1 [check_mod_type_wf] checking that types are well-formed in top-level module
6-
end of query stack
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0283`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// check-pass
3+
4+
// Checks that we don't explode when we assemble >1 candidate for a goal.
5+
6+
struct Wrapper<T>(T);
7+
8+
trait Foo {}
9+
10+
impl Foo for Wrapper<i32> {}
11+
12+
impl Foo for Wrapper<()> {}
13+
14+
fn needs_foo(_: impl Foo) {}
15+
16+
fn main() {
17+
let mut x = Default::default();
18+
let w = Wrapper(x);
19+
needs_foo(w);
20+
x = 1;
21+
drop(x);
22+
}

0 commit comments

Comments
 (0)