Skip to content

Commit ac883ef

Browse files
Prefer candidates with no external constrains in new solver
1 parent d012d2f commit ac883ef

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

compiler/rustc_trait_selection/src/solve/assembly.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Code shared by trait and projection goals for candidate assembly.
22
3+
use crate::solve::CanonicalResponseExt;
4+
35
#[cfg(doc)]
46
use super::trait_goals::structural_traits::*;
57
use super::{EvalCtxt, SolverMode};
@@ -18,7 +20,7 @@ use std::fmt::Debug;
1820
///
1921
/// It consists of both the `source`, which describes how that goal would be proven,
2022
/// and the `result` when using the given `source`.
21-
#[derive(Debug, Clone)]
23+
#[derive(Debug, Clone, Copy)]
2224
pub(super) struct Candidate<'tcx> {
2325
pub(super) source: CandidateSource,
2426
pub(super) result: CanonicalResponse<'tcx>,
@@ -510,12 +512,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
510512
&mut self,
511513
mut candidates: Vec<Candidate<'tcx>>,
512514
) -> QueryResult<'tcx> {
513-
match candidates.len() {
514-
0 => return Err(NoSolution),
515-
1 => return Ok(candidates.pop().unwrap().result),
515+
match &candidates[..] {
516+
[] => return Err(NoSolution),
517+
[candidate] => return Ok(candidate.result),
516518
_ => {}
517519
}
518520

521+
if let Some(candidate) = candidates.iter().find(|candidate| {
522+
candidate.result.value.certainty == Certainty::Yes
523+
&& candidate.result.has_no_inference_or_external_constraints()
524+
}) {
525+
return Ok(candidate.result);
526+
}
527+
519528
if candidates.len() > 1 {
520529
let mut i = 0;
521530
'outer: while i < candidates.len() {

compiler/rustc_trait_selection/src/solve/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
// FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
1313

14+
use itertools::Itertools;
1415
use rustc_hir::def_id::DefId;
1516
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
1617
use rustc_infer::traits::query::NoSolution;
@@ -300,9 +301,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
300301

301302
// FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with
302303
// a subset of the constraints that all the other responses have.
303-
let one = candidates[0];
304-
if candidates[1..].iter().all(|resp| resp == &one) {
305-
return Ok(one);
304+
if candidates.iter().all_equal() {
305+
return Ok(candidates[0]);
306306
}
307307

308308
if let Some(response) = candidates.iter().find(|response| {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// check-pass
3+
4+
trait Foo {}
5+
6+
impl<T> Foo for T {}
7+
8+
trait Bar {}
9+
10+
struct Wrapper<'a, T>(&'a T);
11+
12+
impl<'a, T> Bar for Wrapper<'a, T> where &'a T: Foo {}
13+
// We need to satisfy `&'a T: Foo` when checking that this impl is WF
14+
// that can either be satisfied via the param-env, or via an impl.
15+
//
16+
// When satisfied via the param-env, since each lifetime is canonicalized
17+
// separately, we end up getting extra region constraints.
18+
//
19+
// However, when satisfied via the impl, there are no region constraints,
20+
// and we can short-circuit a response with no external constraints.
21+
22+
fn main() {}

0 commit comments

Comments
 (0)