Skip to content

Commit fd0dfd3

Browse files
Rollup merge of rust-lang#107102 - compiler-errors:new-solver-new-candidats-4, r=lcnr
Implement some more predicates in the new solver Implement a few more goals. The subtype goal specifically is important, since it's required for this code to compile: ``` fn main() { let mut x = vec![]; x.push(1i32); } ``` (I think we emit a subtype goal here because of coercion). Drive-by: Also implements `--compare-mode=next-solver` -- I've been using this locally a lot to find out what works and what doesn't. I'm also happy to split this out into another PR. r? ``@lcnr``
2 parents 10057f5 + 444cbcd commit fd0dfd3

File tree

7 files changed

+91
-18
lines changed

7 files changed

+91
-18
lines changed

compiler/rustc_trait_selection/src/solve/assembly.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Code shared by trait and projection goals for candidate assembly.
22
33
use super::infcx_ext::InferCtxtExt;
4-
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
4+
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
55
use rustc_hir::def_id::DefId;
66
use rustc_infer::traits::query::NoSolution;
77
use rustc_infer::traits::util::elaborate_predicates;
@@ -148,9 +148,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
148148
if goal.predicate.self_ty().is_ty_var() {
149149
return vec![Candidate {
150150
source: CandidateSource::BuiltinImpl,
151-
result: self
152-
.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity))
153-
.unwrap(),
151+
result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(),
154152
}];
155153
}
156154

compiler/rustc_trait_selection/src/solve/mod.rs

+76-7
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@
1919

2020
use std::mem;
2121

22+
use rustc_hir::def_id::DefId;
2223
use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
2324
use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
2425
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
2526
use rustc_infer::traits::query::NoSolution;
2627
use rustc_infer::traits::Obligation;
2728
use rustc_middle::infer::canonical::Certainty as OldCertainty;
2829
use rustc_middle::ty::{self, Ty, TyCtxt};
29-
use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
30+
use rustc_middle::ty::{
31+
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate,
32+
};
3033
use rustc_span::DUMMY_SP;
3134

3235
use crate::traits::ObligationCause;
@@ -87,6 +90,8 @@ pub enum Certainty {
8790
}
8891

8992
impl Certainty {
93+
pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
94+
9095
/// When proving multiple goals using **AND**, e.g. nested obligations for an impl,
9196
/// use this function to unify the certainty of these goals
9297
pub fn unify_and(self, other: Certainty) -> Certainty {
@@ -243,16 +248,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
243248
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => {
244249
self.compute_region_outlives_goal(Goal { param_env, predicate })
245250
}
251+
ty::PredicateKind::Subtype(predicate) => {
252+
self.compute_subtype_goal(Goal { param_env, predicate })
253+
}
254+
ty::PredicateKind::Coerce(predicate) => {
255+
self.compute_coerce_goal(Goal { param_env, predicate })
256+
}
257+
ty::PredicateKind::ClosureKind(def_id, substs, kind) => self
258+
.compute_closure_kind_goal(Goal {
259+
param_env,
260+
predicate: (def_id, substs, kind),
261+
}),
262+
ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS),
246263
// FIXME: implement these predicates :)
247264
ty::PredicateKind::WellFormed(_)
248265
| ty::PredicateKind::ObjectSafe(_)
249-
| ty::PredicateKind::ClosureKind(_, _, _)
250-
| ty::PredicateKind::Subtype(_)
251-
| ty::PredicateKind::Coerce(_)
252266
| ty::PredicateKind::ConstEvaluatable(_)
253-
| ty::PredicateKind::ConstEquate(_, _)
254-
| ty::PredicateKind::TypeWellFormedFromEnv(_)
255-
| ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::Yes),
267+
| ty::PredicateKind::ConstEquate(_, _) => {
268+
self.make_canonical_response(Certainty::Yes)
269+
}
270+
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
271+
bug!("TypeWellFormedFromEnv is only used for Chalk")
272+
}
256273
}
257274
} else {
258275
let kind = self.infcx.replace_bound_vars_with_placeholders(kind);
@@ -275,6 +292,58 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
275292
) -> QueryResult<'tcx> {
276293
self.make_canonical_response(Certainty::Yes)
277294
}
295+
296+
fn compute_coerce_goal(
297+
&mut self,
298+
goal: Goal<'tcx, CoercePredicate<'tcx>>,
299+
) -> QueryResult<'tcx> {
300+
self.compute_subtype_goal(Goal {
301+
param_env: goal.param_env,
302+
predicate: SubtypePredicate {
303+
a_is_expected: false,
304+
a: goal.predicate.a,
305+
b: goal.predicate.b,
306+
},
307+
})
308+
}
309+
310+
fn compute_subtype_goal(
311+
&mut self,
312+
goal: Goal<'tcx, SubtypePredicate<'tcx>>,
313+
) -> QueryResult<'tcx> {
314+
if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
315+
// FIXME: Do we want to register a subtype relation between these vars?
316+
// That won't actually reflect in the query response, so it seems moot.
317+
self.make_canonical_response(Certainty::AMBIGUOUS)
318+
} else {
319+
self.infcx.probe(|_| {
320+
let InferOk { value: (), obligations } = self
321+
.infcx
322+
.at(&ObligationCause::dummy(), goal.param_env)
323+
.sub(goal.predicate.a, goal.predicate.b)?;
324+
self.evaluate_all_and_make_canonical_response(
325+
obligations.into_iter().map(|pred| pred.into()).collect(),
326+
)
327+
})
328+
}
329+
}
330+
331+
fn compute_closure_kind_goal(
332+
&mut self,
333+
goal: Goal<'tcx, (DefId, ty::SubstsRef<'tcx>, ty::ClosureKind)>,
334+
) -> QueryResult<'tcx> {
335+
let (_, substs, expected_kind) = goal.predicate;
336+
let found_kind = substs.as_closure().kind_ty().to_opt_closure_kind();
337+
338+
let Some(found_kind) = found_kind else {
339+
return self.make_canonical_response(Certainty::AMBIGUOUS);
340+
};
341+
if found_kind.extends(expected_kind) {
342+
self.make_canonical_response(Certainty::Yes)
343+
} else {
344+
Err(NoSolution)
345+
}
346+
}
278347
}
279348

280349
impl<'tcx> EvalCtxt<'_, 'tcx> {

compiler/rustc_trait_selection/src/solve/project_goals.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::traits::{specialization_graph, translate_substs};
33
use super::assembly::{self, Candidate, CandidateSource};
44
use super::infcx_ext::InferCtxtExt;
55
use super::trait_goals::structural_traits;
6-
use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
6+
use super::{Certainty, EvalCtxt, Goal, QueryResult};
77
use rustc_errors::ErrorGuaranteed;
88
use rustc_hir::def::DefKind;
99
use rustc_hir::def_id::DefId;
@@ -229,8 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
229229
goal.predicate.def_id(),
230230
impl_def_id
231231
)? else {
232-
let certainty = Certainty::Maybe(MaybeCause::Ambiguity);
233-
return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty));
232+
return ecx.make_canonical_response(trait_ref_certainty.unify_and(Certainty::AMBIGUOUS));
234233
};
235234

236235
if !assoc_def.item.defaultness(tcx).has_value() {
@@ -382,7 +381,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
382381
.to_predicate(ecx.tcx());
383382
Self::consider_assumption(ecx, goal, pred)
384383
} else {
385-
ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity))
384+
ecx.make_canonical_response(Certainty::AMBIGUOUS)
386385
}
387386
}
388387

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::iter;
44

55
use super::assembly::{self, Candidate, CandidateSource};
66
use super::infcx_ext::InferCtxtExt;
7-
use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
7+
use super::{Certainty, EvalCtxt, Goal, QueryResult};
88
use rustc_hir::def_id::DefId;
99
use rustc_infer::infer::InferCtxt;
1010
use rustc_infer::traits::query::NoSolution;
@@ -133,7 +133,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
133133
goal: Goal<'tcx, Self>,
134134
) -> QueryResult<'tcx> {
135135
if goal.predicate.self_ty().has_non_region_infer() {
136-
return ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity));
136+
return ecx.make_canonical_response(Certainty::AMBIGUOUS);
137137
}
138138

139139
let tcx = ecx.tcx();
@@ -171,7 +171,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
171171
.to_predicate(ecx.tcx());
172172
Self::consider_assumption(ecx, goal, pred)
173173
} else {
174-
ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity))
174+
ecx.make_canonical_response(Certainty::AMBIGUOUS)
175175
}
176176
}
177177

src/tools/compiletest/src/common.rs

+3
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ pub enum FailMode {
123123
pub enum CompareMode {
124124
Polonius,
125125
Chalk,
126+
NextSolver,
126127
SplitDwarf,
127128
SplitDwarfSingle,
128129
}
@@ -132,6 +133,7 @@ impl CompareMode {
132133
match *self {
133134
CompareMode::Polonius => "polonius",
134135
CompareMode::Chalk => "chalk",
136+
CompareMode::NextSolver => "next-solver",
135137
CompareMode::SplitDwarf => "split-dwarf",
136138
CompareMode::SplitDwarfSingle => "split-dwarf-single",
137139
}
@@ -141,6 +143,7 @@ impl CompareMode {
141143
match s.as_str() {
142144
"polonius" => CompareMode::Polonius,
143145
"chalk" => CompareMode::Chalk,
146+
"next-solver" => CompareMode::NextSolver,
144147
"split-dwarf" => CompareMode::SplitDwarf,
145148
"split-dwarf-single" => CompareMode::SplitDwarfSingle,
146149
x => panic!("unknown --compare-mode option: {}", x),

src/tools/compiletest/src/header.rs

+1
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ impl Config {
710710
match self.compare_mode {
711711
Some(CompareMode::Polonius) => name == "compare-mode-polonius",
712712
Some(CompareMode::Chalk) => name == "compare-mode-chalk",
713+
Some(CompareMode::NextSolver) => name == "compare-mode-next-solver",
713714
Some(CompareMode::SplitDwarf) => name == "compare-mode-split-dwarf",
714715
Some(CompareMode::SplitDwarfSingle) => name == "compare-mode-split-dwarf-single",
715716
None => false,

src/tools/compiletest/src/runtest.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,9 @@ impl<'test> TestCx<'test> {
20302030
Some(CompareMode::Chalk) => {
20312031
rustc.args(&["-Ztrait-solver=chalk"]);
20322032
}
2033+
Some(CompareMode::NextSolver) => {
2034+
rustc.args(&["-Ztrait-solver=next"]);
2035+
}
20332036
Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => {
20342037
rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
20352038
}

0 commit comments

Comments
 (0)